From 864ea2c24ca8cbac690e86f97eefbf1686783535 Mon Sep 17 00:00:00 2001 From: Troy Dawson Date: Thu, 15 Oct 2020 10:06:29 -0700 Subject: [PATCH] RHEL 9.0.0 Alpha bootstrap The content of this branch was automatically imported from Fedora ELN with the following as its source: https://src.fedoraproject.org/rpms/sudo#68203ed1a2fac7aff1b57189e8c217db89e5fe4a --- .gitignore | 27 + sources | 1 + sudo-1.6.7p5-strip.patch | 11 + sudo.rpmlintrc | 16 + sudo.spec | 1016 +++++++++++++++++ sudoers | 120 ++ tests/fully-qualified-hostnames/Makefile | 71 ++ tests/fully-qualified-hostnames/PURPOSE | 3 + tests/fully-qualified-hostnames/runtest.sh | 106 ++ tests/fully-qualified-hostnames/ssh-sudo.exp | 20 + tests/run-as/Makefile | 68 ++ tests/run-as/PURPOSE | 3 + .../distribution/Library/Cleanup/Makefile | 59 + .../distribution/Library/Cleanup/lib.sh | 314 +++++ .../Library/ConditionalPhases/Makefile | 59 + .../Library/ConditionalPhases/lib.sh | 166 +++ .../run-as/distribution/Library/Log/Makefile | 48 + tests/run-as/distribution/Library/Log/lib.sh | 637 +++++++++++ .../run-as/distribution/Library/opts/Makefile | 48 + tests/run-as/distribution/Library/opts/lib.sh | 338 ++++++ .../run-as/distribution/Library/tcf/Makefile | 60 + tests/run-as/distribution/Library/tcf/lib.sh | 903 +++++++++++++++ .../distribution/Library/testUser/Makefile | 60 + .../distribution/Library/testUser/lib.sh | 234 ++++ tests/run-as/runtest.sh | 163 +++ tests/sudoers-options-sanity-test/Makefile | 67 ++ tests/sudoers-options-sanity-test/PURPOSE | 3 + .../distribution/Library/Cleanup/Makefile | 59 + .../distribution/Library/Cleanup/lib.sh | 314 +++++ .../Library/ConditionalPhases/Makefile | 59 + .../Library/ConditionalPhases/lib.sh | 166 +++ .../distribution/Library/Log/Makefile | 48 + .../distribution/Library/Log/lib.sh | 637 +++++++++++ .../distribution/Library/opts/Makefile | 48 + .../distribution/Library/opts/lib.sh | 338 ++++++ .../distribution/Library/tcf/Makefile | 60 + .../distribution/Library/tcf/lib.sh | 903 +++++++++++++++ .../distribution/Library/testUser/Makefile | 60 + .../distribution/Library/testUser/lib.sh | 234 ++++ tests/sudoers-options-sanity-test/runtest.sh | 379 ++++++ tests/tests.yml | 53 + .../Makefile | 70 ++ .../PURPOSE | 3 + .../runtest.sh | 80 ++ tests/use_pty-option/Makefile | 72 ++ tests/use_pty-option/PURPOSE | 4 + tests/use_pty-option/forker.sh | 5 + tests/use_pty-option/runtest.sh | 76 ++ tests/use_pty-option/ssh-sudo.exp | 20 + 49 files changed, 8309 insertions(+) create mode 100644 sources create mode 100644 sudo-1.6.7p5-strip.patch create mode 100644 sudo.rpmlintrc create mode 100644 sudo.spec create mode 100644 sudoers create mode 100644 tests/fully-qualified-hostnames/Makefile create mode 100644 tests/fully-qualified-hostnames/PURPOSE create mode 100755 tests/fully-qualified-hostnames/runtest.sh create mode 100755 tests/fully-qualified-hostnames/ssh-sudo.exp create mode 100644 tests/run-as/Makefile create mode 100644 tests/run-as/PURPOSE create mode 100644 tests/run-as/distribution/Library/Cleanup/Makefile create mode 100644 tests/run-as/distribution/Library/Cleanup/lib.sh create mode 100644 tests/run-as/distribution/Library/ConditionalPhases/Makefile create mode 100644 tests/run-as/distribution/Library/ConditionalPhases/lib.sh create mode 100644 tests/run-as/distribution/Library/Log/Makefile create mode 100644 tests/run-as/distribution/Library/Log/lib.sh create mode 100644 tests/run-as/distribution/Library/opts/Makefile create mode 100644 tests/run-as/distribution/Library/opts/lib.sh create mode 100644 tests/run-as/distribution/Library/tcf/Makefile create mode 100644 tests/run-as/distribution/Library/tcf/lib.sh create mode 100644 tests/run-as/distribution/Library/testUser/Makefile create mode 100644 tests/run-as/distribution/Library/testUser/lib.sh create mode 100755 tests/run-as/runtest.sh create mode 100644 tests/sudoers-options-sanity-test/Makefile create mode 100644 tests/sudoers-options-sanity-test/PURPOSE create mode 100644 tests/sudoers-options-sanity-test/distribution/Library/Cleanup/Makefile create mode 100644 tests/sudoers-options-sanity-test/distribution/Library/Cleanup/lib.sh create mode 100644 tests/sudoers-options-sanity-test/distribution/Library/ConditionalPhases/Makefile create mode 100644 tests/sudoers-options-sanity-test/distribution/Library/ConditionalPhases/lib.sh create mode 100644 tests/sudoers-options-sanity-test/distribution/Library/Log/Makefile create mode 100644 tests/sudoers-options-sanity-test/distribution/Library/Log/lib.sh create mode 100644 tests/sudoers-options-sanity-test/distribution/Library/opts/Makefile create mode 100644 tests/sudoers-options-sanity-test/distribution/Library/opts/lib.sh create mode 100644 tests/sudoers-options-sanity-test/distribution/Library/tcf/Makefile create mode 100644 tests/sudoers-options-sanity-test/distribution/Library/tcf/lib.sh create mode 100644 tests/sudoers-options-sanity-test/distribution/Library/testUser/Makefile create mode 100644 tests/sudoers-options-sanity-test/distribution/Library/testUser/lib.sh create mode 100755 tests/sudoers-options-sanity-test/runtest.sh create mode 100644 tests/tests.yml create mode 100644 tests/upstream-testsuite-execution-and-rebuild-test/Makefile create mode 100644 tests/upstream-testsuite-execution-and-rebuild-test/PURPOSE create mode 100755 tests/upstream-testsuite-execution-and-rebuild-test/runtest.sh create mode 100644 tests/use_pty-option/Makefile create mode 100644 tests/use_pty-option/PURPOSE create mode 100644 tests/use_pty-option/forker.sh create mode 100755 tests/use_pty-option/runtest.sh create mode 100755 tests/use_pty-option/ssh-sudo.exp diff --git a/.gitignore b/.gitignore index e69de29..cbf6389 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,27 @@ +/sudo-1.8.16.tar.gz +/sudo-1.8.17p1.tar.gz +/sudo-1.8.18b2.tar.gz +/sudo-1.8.18rc2.tar.gz +/sudo-1.8.18rc4.tar.gz +/sudo-1.8.18.tar.gz +/sudo-90e4538c001fbe1b791a11d6a2c37607472fafe5.tar.gz +/sudo-738c3cbf3e8400bf4a5aeab8966427ff6d630cd2.tar.gz +/sudo-1.8.19p2.tar.gz +/sudo-1.8.20b1.tar.gz +/sudo-1.8.20p1.tar.gz +/sudo-1.8.20p2.tar.gz +/sudo-1.8.21p2.tar.gz +/sudo-1.8.22b1.tar.gz +/sudo-1.8.23b3.tar.gz +/sudo-1.8.23.tar.gz +/sudo-1.8.25.tar.gz +/sudo-1.8.25p1.tar.gz +/sudo-1.8.27.tar.gz +/sudo-1.8.28.tar.gz +/sudo-1.8.28p1.tar.gz +/sudo-1.8.29.tar.gz +/sudo-1.9.0b1.tar.gz +/sudo-1.9.0b4.tar.gz +/sudo-1.9.1.tar.gz +/sudo-1.9.2.tar.gz +/sudo-1.9.3p1.tar.gz diff --git a/sources b/sources new file mode 100644 index 0000000..2a74432 --- /dev/null +++ b/sources @@ -0,0 +1 @@ +SHA512 (sudo-1.9.3p1.tar.gz) = 3ad13fd03e5b371fd6bf7909731ffc11431d2182a744b654f7e5d4b810e47955d49bc78f551afe13ec56acbce694139c33a15bc022cea41b17af5496b8b7f89f diff --git a/sudo-1.6.7p5-strip.patch b/sudo-1.6.7p5-strip.patch new file mode 100644 index 0000000..f9e2faa --- /dev/null +++ b/sudo-1.6.7p5-strip.patch @@ -0,0 +1,11 @@ +--- sudo-1.6.7p5/install-sh.strip 2005-07-21 14:28:25.000000000 +0200 ++++ sudo-1.6.7p5/install-sh 2005-07-21 14:29:18.000000000 +0200 +@@ -138,7 +138,7 @@ + fi + ;; + X-s) +- STRIPIT=true ++ #STRIPIT=true + ;; + X--) + shift diff --git a/sudo.rpmlintrc b/sudo.rpmlintrc new file mode 100644 index 0000000..d7c57d7 --- /dev/null +++ b/sudo.rpmlintrc @@ -0,0 +1,16 @@ +# Sudo allows restricted root access for specified users. In other words, +# it is a special package, which requires special permissions on on some +# of the installed files. +addFilter("missing-call-to-setgroups-before-setuid (/usr/bin/sudo|/usr/bin/sudoreplay|/usr/sbin/sudo_logsrvd|/usr/sbin/sudo_sendlog|/usr/libexec/sudo/sudoers.so|)$") + +addFilter("non-readable (/etc/sudo.conf|/etc/sudo_logsrvd.conf|/etc/sudoers|/usr/bin/sudoreplay) .*$") + +addFilter("non-standard-dir-perm (/etc/sudoers.d|/var/db/sudo|/var/db/sudo/lectured) .*$") + +addFilter("setuid-binary /usr/bin/sudo .*$") + +addFilter("non-standard-executable-perm (/usr/bin/sudo|/usr/bin/sudoreplay) .*$") + +addFilter("wrong-file-end-of-line-encoding /usr/share/doc/sudo/schema.ActiveDirectory$") + +addFilter("non-standard-dir-in-var db$") diff --git a/sudo.spec b/sudo.spec new file mode 100644 index 0000000..0089dfe --- /dev/null +++ b/sudo.spec @@ -0,0 +1,1016 @@ +Summary: Allows restricted root access for specified users +Name: sudo +Version: 1.9.3p1 +Release: 1%{?dist} +License: ISC +URL: http://www.courtesan.com/sudo/ +Source0: https://www.sudo.ws/dist/%{name}-%{version}.tar.gz +Source1: sudoers +Requires: pam +Recommends: vim-minimal +Requires(post): coreutils + +BuildRequires: pam-devel +BuildRequires: groff +BuildRequires: openldap-devel +BuildRequires: flex +BuildRequires: bison +BuildRequires: automake autoconf libtool +BuildRequires: audit-libs-devel libcap-devel +BuildRequires: libselinux-devel +BuildRequires: sendmail +BuildRequires: gettext +BuildRequires: zlib-devel +BuildRequires: python3-devel + +# don't strip +Patch1: sudo-1.6.7p5-strip.patch + +%description +Sudo (superuser do) allows a system administrator to give certain +users (or groups of users) the ability to run some (or all) commands +as root while logging all commands and arguments. Sudo operates on a +per-command basis. It is not a replacement for the shell. Features +include: the ability to restrict what commands a user may run on a +per-host basis, copious logging of each command (providing a clear +audit trail of who did what), a configurable timeout of the sudo +command, and the ability to use the same configuration file (sudoers) +on many different machines. + +%package devel +Summary: Development files for %{name} +Requires: %{name} = %{version}-%{release} + +%description devel +The %{name}-devel package contains header files developing sudo +plugins that use %{name}. + + +%package logsrvd +Summary: High-performance log server for %{name} +Requires: %{name} = %{version}-%{release} +BuildRequires: openssl-devel + + +%description logsrvd +%{name}-logsrvd is a high-performance log server that accepts event and I/O logs from sudo. +It can be used to implement centralized logging of sudo logs. + +%prep +%setup -q + +%patch1 -p1 -b .strip + +%build +# Remove bundled copy of zlib +rm -rf zlib/ +autoreconf -I m4 -fv --install + +%ifarch s390 s390x sparc64 +F_PIE=-fPIE +%else +F_PIE=-fpie +%endif + +export CFLAGS="$RPM_OPT_FLAGS $F_PIE" LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" + +%configure \ + --prefix=%{_prefix} \ + --sbindir=%{_sbindir} \ + --libdir=%{_libdir} \ + --docdir=%{_pkgdocdir} \ + --enable-openssl \ + --disable-root-mailer \ + --with-logging=syslog \ + --with-logfac=authpriv \ + --with-pam \ + --with-pam-login \ + --with-editor=/bin/vi \ + --with-env-editor \ + --with-ignore-dot \ + --with-tty-tickets \ + --with-ldap \ + --with-selinux \ + --with-passprompt="[sudo] password for %p: " \ + --enable-python \ + --with-linux-audit \ + --with-sssd +# --without-kerb5 \ +# --without-kerb4 +make + +%check +make check + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR="$RPM_BUILD_ROOT" install_uid=`id -u` install_gid=`id -g` sudoers_uid=`id -u` sudoers_gid=`id -g` + +chmod 755 $RPM_BUILD_ROOT%{_bindir}/* $RPM_BUILD_ROOT%{_sbindir}/* +install -p -d -m 700 $RPM_BUILD_ROOT/var/db/sudo +install -p -d -m 700 $RPM_BUILD_ROOT/var/db/sudo/lectured +install -p -d -m 750 $RPM_BUILD_ROOT/etc/sudoers.d +install -p -c -m 0440 %{SOURCE1} $RPM_BUILD_ROOT/etc/sudoers +#add sudo to protected packages +install -p -d -m 755 $RPM_BUILD_ROOT/etc/dnf/protected.d/ +touch sudo.conf +echo sudo > sudo.conf +install -p -c -m 0644 sudo.conf $RPM_BUILD_ROOT/etc/dnf/protected.d/ +rm -f sudo.conf + +chmod +x $RPM_BUILD_ROOT%{_libexecdir}/sudo/*.so # for stripping, reset in %%files + +# Don't package LICENSE as a doc +rm -rf $RPM_BUILD_ROOT%{_pkgdocdir}/LICENSE + +# Remove examples; Examples can be found in man pages too. +rm -rf $RPM_BUILD_ROOT%{_datadir}/examples/sudo + +#Remove all .la files +find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' + +# Remove sudoers.dist +rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sudoers.dist + +%find_lang sudo +%find_lang sudoers + +cat sudo.lang sudoers.lang > sudo_all.lang +rm sudo.lang sudoers.lang + +mkdir -p $RPM_BUILD_ROOT/etc/pam.d +cat > $RPM_BUILD_ROOT/etc/pam.d/sudo << EOF +#%%PAM-1.0 +auth include system-auth +account include system-auth +password include system-auth +session optional pam_keyinit.so revoke +session required pam_limits.so +session include system-auth +EOF + +cat > $RPM_BUILD_ROOT/etc/pam.d/sudo-i << EOF +#%%PAM-1.0 +auth include sudo +account include sudo +password include sudo +session optional pam_keyinit.so force revoke +session include sudo +EOF + + +%files -f sudo_all.lang +%defattr(-,root,root) +%attr(0440,root,root) %config(noreplace) /etc/sudoers +%attr(0750,root,root) %dir /etc/sudoers.d/ +%config(noreplace) /etc/pam.d/sudo +%config(noreplace) /etc/pam.d/sudo-i +%attr(0644,root,root) %{_tmpfilesdir}/sudo.conf +%attr(0644,root,root) %config(noreplace) /etc/dnf/protected.d/sudo.conf +%attr(0640,root,root) %config(noreplace) /etc/sudo.conf +%dir /var/db/sudo +%dir /var/db/sudo/lectured +%attr(4111,root,root) %{_bindir}/sudo +%{_bindir}/sudoedit +%attr(0111,root,root) %{_bindir}/sudoreplay +%attr(0755,root,root) %{_sbindir}/visudo +%{_bindir}/cvtsudoers +%dir %{_libexecdir}/sudo +%attr(0755,root,root) %{_libexecdir}/sudo/sesh +%attr(0644,root,root) %{_libexecdir}/sudo/sudo_noexec.so +%attr(0644,root,root) %{_libexecdir}/sudo/sudoers.so +%attr(0644,root,root) %{_libexecdir}/sudo/audit_json.so +%attr(0644,root,root) %{_libexecdir}/sudo/group_file.so +%attr(0644,root,root) %{_libexecdir}/sudo/python_plugin.so +%attr(0644,root,root) %{_libexecdir}/sudo/sample_approval.so +%attr(0644,root,root) %{_libexecdir}/sudo/system_group.so +%attr(0644,root,root) %{_libexecdir}/sudo/libsudo_util.so.?.?.? +%{_libexecdir}/sudo/libsudo_util.so.? +%{_libexecdir}/sudo/libsudo_util.so +%{_mandir}/man5/sudoers.5* +%{_mandir}/man5/sudoers.ldap.5* +%{_mandir}/man5/sudo.conf.5* +%{_mandir}/man8/sudo.8* +%{_mandir}/man8/sudoedit.8* +%{_mandir}/man8/sudoreplay.8* +%{_mandir}/man8/visudo.8* +%{_mandir}/man1/cvtsudoers.1.gz +%{_mandir}/man5/sudoers_timestamp.5.gz +%{_mandir}/man8/sudo_plugin_python.8.gz +%dir %{_pkgdocdir}/ +%{_pkgdocdir}/* +%{!?_licensedir:%global license %%doc} +%license doc/LICENSE +%exclude %{_pkgdocdir}/ChangeLog + +%files devel +%doc plugins/sample/sample_plugin.c +%{_includedir}/sudo_plugin.h +%{_mandir}/man8/sudo_plugin.8* + +%files logsrvd +%attr(0640,root,root) %config(noreplace) /etc/sudo_logsrvd.conf +%attr(0755,root,root) %{_sbindir}/sudo_logsrvd +%attr(0755,root,root) %{_sbindir}/sudo_sendlog +%{_mandir}/man5/sudo_logsrv.proto.5.gz +%{_mandir}/man5/sudo_logsrvd.conf.5.gz +%{_mandir}/man8/sudo_logsrvd.8.gz +%{_mandir}/man8/sudo_sendlog.8.gz + +%changelog +* Mon Oct 05 2020 Radovan Sroka - 1.9.3p1-1 +- rebase to 1.9.3p1 +- enable python modules +Resolves: rhbz#1881112 + +* Tue Sep 15 2020 Radovan Sroka - 1.9.2-1 +- rebase to 1.9.2 +Resolves: rhbz#1859577 +- added logsrvd subpackage +- added openssl-devel buildrequires +Resolves: rhbz#1860653 +- fixed sudo runstatedir path +- it was generated as /sudo instead of /run/sudo +Resolves: rhbz#1868215 +- added /var/lib/snapd/snap/bin to secure_path variable +Resolves: rhbz#1691996 + +* Sat Aug 01 2020 Fedora Release Engineering - 1.9.1-3 +- Second attempt - Rebuilt for + https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Wed Jul 29 2020 Fedora Release Engineering - 1.9.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Wed Jul 08 2020 Attila Lakatos - 1.9.1-1 +- rebase to 1.9.1 +Resolves: rhbz#1848788 +- fix rpmlint errors +Resolves: rhbz#1817139 + +* Wed Mar 25 2020 Attila Lakatos - 1.9.0-0.1.b4 +- update to latest development version 1.9.0b4 +Resolves: rhbz#1816593 +- setrlimit(RLIMIT_CORE): Operation not permitted warning message fix +Resolves: rhbz#1773148 + +* Mon Feb 24 2020 Attila Lakatos - 1.9.0-0.1.b1 +- update to latest development version 1.9.0b1 +- added sudo_logsrvd and sudo_sendlog to files and their appropriate man pages +Resolves: rhbz#1787823 +- Stack based buffer overflow in when pwfeedback is enabled +Resolves: rhbz#1796945 +- fixes: CVE-2019-18634 +- By using ! character in the shadow file instead of a password hash can access to a run as all sudoer account +Resolves: rhbz#1786709 +- fixes CVE-2019-19234 +- attacker with access to a Runas ALL sudoer account can impersonate a nonexistent user +Resolves: rhbz#1786705 +- fixes CVE-2019-19232 + +* Fri Jan 31 2020 Fedora Release Engineering - 1.8.29-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Mon Nov 11 2019 Radovan Sroka - 1.8.29-1 +- rebase to 1.8.29 +Resolves: rhbz#1766233 + +* Tue Oct 22 2019 Radovan Sroka - 1.8.28p1-1 +- rebase to 1.8.28p1 +Resolves: rhbz#1762350 + +* Tue Oct 15 2019 Radovan Sroka - 1.8.28-1 +- rebase to 1.8.28 +Resolves: rhbz#1761533 +- set always_set_home by default +Resolves: rhbz#1728687 +- Sync sudoers options from rhel8 to fedora +Resolves: rhbz#1761781 +- CVE-2019-14287 +Resolves: rhbz#1761584 + +* Sat Jul 27 2019 Fedora Release Engineering - 1.8.27-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Sun Mar 31 2019 Marek Tamaskovic 1.8.27-2 +- resolves rhbz#1676925 +- Removed PS1, PS2 from sudoers + +* Mon Mar 11 2019 Radovan Sroka 1.8.27-1 +- rebase sudo to 1.8.27 + +* Sun Feb 03 2019 Fedora Release Engineering - 1.8.25p1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Mon Oct 01 2018 Radovan Sroka 1.8.25p1-1 +- rebase sudo to 1.8.25p1 + +* Mon Sep 10 2018 Radovan Sroka 1.8.25-1 +- rebase sudo to latest stawble version +- install /etc/dnf/protected.d/sudo instead of /etc/yum/protected.d/sudo (1626968) + +* Sat Jul 14 2018 Fedora Release Engineering - 1.8.23-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Tue Jul 03 2018 Matthew Miller - 1.8.23-2 +- remove defattr, as default is now sane + +* Wed May 09 2018 Daniel Kopecek - 1.8.23-1 +- update to 1.8.23 + +* Wed Apr 18 2018 Daniel Kopecek - 1.8.23-0.1.b3 +- update to 1.8.23b3 + +* Fri Feb 09 2018 Fedora Release Engineering - 1.8.22-0.2.b1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Thu Dec 14 2017 Radovan Sroka - 1.8.22b1-1 +- update to 1.8.22b1 +- Added /usr/local/sbin and /usr/local/bin to secure path rhbz#1166185 + +* Thu Sep 21 2017 Marek Tamaskovic - 1.8.21p2-1 +- update to 1.8.21p2 +- Moved libsudo_util.so from the -devel sub-package to main package (1481225) + +* Wed Sep 06 2017 Matthew Miller - 1.8.20p2-4 +- replace file-based requirements with package-level ones: +- /etc/pam.d/system-auth to 'pam' +- /bin/chmod to 'coreutils' (bug #1488934) +- /usr/bin/vi to vim-minimal +- ... and make vim-minimal "recommends" instead of "requires", because + other editors can be configured. + +* Thu Aug 03 2017 Fedora Release Engineering - 1.8.20p2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Thu Jul 27 2017 Fedora Release Engineering - 1.8.20p2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Thu Jun 01 2017 Daniel Kopecek 1.8.20p2-1 +- update to 1.8.20p2 + +* Wed May 31 2017 Daniel Kopecek 1.8.20p1-1 +- update to 1.8.20p1 +- fixes CVE-2017-1000367 + Resolves: rhbz#1456884 + +* Fri Apr 07 2017 Jiri Vymazal - 1.8.20-0.1.b1 +- update to latest development version 1.8.20b1 +- added sudo to dnf/yum protected packages + Resolves: rhbz#1418756 + +* Mon Feb 13 2017 Tomas Sykora - 1.8.19p2-1 +- update to 1.8.19p2 + +* Sat Feb 11 2017 Fedora Release Engineering - 1.8.19-0.3.20161108git738c3cb +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Tue Nov 08 2016 Daniel Kopecek 1.8.19-0.2.20161108git738c3cb +- update to latest development version +- fixes CVE-2016-7076 + +* Fri Sep 23 2016 Radovan Sroka 1.8.19-0.1.20160923git90e4538 +- we were not able to update from rc and beta versions to stable one +- so this is a new snapshot package which resolves it + +* Wed Sep 21 2016 Radovan Sroka 1.8.18-1 +- update to 1.8.18 + +* Fri Sep 16 2016 Radovan Sroka 1.8.18rc4-1 +- update to 1.8.18rc4 + +* Wed Sep 14 2016 Radovan Sroka 1.8.18rc2-1 +- update to 1.8.18rc2 +- dropped sudo-1.8.14p1-ldapconfpatch.patch + upstreamed --> https://www.sudo.ws/pipermail/sudo-workers/2016-September/001006.html + +* Fri Aug 26 2016 Radovan Sroka 1.8.18b2-1 +- update to 1.8.18b2 +- added --disable-root-mailer as configure option + Resolves: rhbz#1324091 + +* Fri Jun 24 2016 Daniel Kopecek 1.8.17p1-1 +- update to 1.8.17p1 +- install the /var/db/sudo/lectured + Resolves: rhbz#1321414 + +* Tue May 31 2016 Daniel Kopecek 1.8.16-4 +- removed INPUTRC from env_keep to prevent a possible info leak + Resolves: rhbz#1340701 + +* Fri May 13 2016 Daniel Kopecek 1.8.16-3 +- fixed upstream patch for rhbz#1328735 + +* Thu May 12 2016 Daniel Kopecek 1.8.16-2 +- fixed invalid sesh argument array construction + +* Mon Apr 04 2016 Daniel Kopecek 1.8.16-1 +- update to 1.8.16 + +* Fri Feb 05 2016 Fedora Release Engineering - 1.8.15-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Thu Nov 5 2015 Daniel Kopecek 1.8.15-1 +- update to 1.8.15 +- fixes CVE-2015-5602 + +* Mon Aug 24 2015 Radovan Sroka 1.8.14p3-3 +- enable upstream test suite + +* Mon Aug 24 2015 Radovan Sroka 1.8.14p3-2 +- add patch that resolves initialization problem before sudo_strsplit call +- add patch that resolves deadcode in visudo.c +- add patch that removes extra while in visudo.c and sudoers.c + +* Mon Jul 27 2015 Radovan Sroka 1.8.14p3-1 +- update to 1.8.14p3 + +* Mon Jul 20 2015 Radovan Sroka 1.8.14p1-1 +- update to 1.8.14p1-1 +- rebase sudo-1.8.14b3-ldapconfpatch.patch -> sudo-1.8.14p1-ldapconfpatch.patch +- rebase sudo-1.8.14b4-docpassexpire.patch -> sudo-1.8.14p1-docpassexpire.patch + +* Tue Jul 14 2015 Radovan Sroka 1.8.12-2 +- add patch3 sudo.1.8.14b4-passexpire.patch that makes change in documentation about timestamp_time +- Resolves: rhbz#1162070 + +* Fri Jul 10 2015 Radovan Sroka - 1.8.14b4-1 +- Update to 1.8.14b4 +- Add own %%{_tmpfilesdir}/sudo.conf + +* Fri Jun 19 2015 Fedora Release Engineering - 1.8.12-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Wed Feb 18 2015 Daniel Kopecek - 1.8.12 +- update to 1.8.12 +- fixes CVE-2014-9680 + +* Mon Nov 3 2014 Daniel Kopecek - 1.8.11p2-1 +- update to 1.8.11p2 +- added patch to fix upstream bug #671 -- exiting immediately + when audit is disabled + +* Tue Sep 30 2014 Daniel Kopecek - 1.8.11-1 +- update to 1.8.11 +- major changes & fixes: + - when running a command in the background, sudo will now forward + SIGINFO to the command + - the passwords in ldap.conf and ldap.secret may now be encoded in base64. + - SELinux role changes are now audited. For sudoedit, we now audit + the actual editor being run, instead of just the sudoedit command. + - it is now possible to match an environment variable's value as well as + its name using env_keep and env_check + - new files created via sudoedit as a non-root user now have the proper group id + - sudoedit now works correctly in conjunction with sudo's SELinux RBAC support + - it is now possible to disable network interface probing in sudo.conf by + changing the value of the probe_interfaces setting + - when listing a user's privileges (sudo -l), the sudoers plugin will now prompt + for the user's password even if the targetpw, rootpw or runaspw options are set. + - the new use_netgroups sudoers option can be used to explicitly enable or disable + netgroups support + - visudo can now export a sudoers file in JSON format using the new -x flag +- added patch to read ldap.conf more closely to nss_ldap +- require /usr/bin/vi instead of vim-minimal +- include pam.d/system-auth in PAM session phase from pam.d/sudo +- include pam.d/sudo in PAM session phase from pam.d/sudo-i + +* Tue Aug 5 2014 Tom Callaway - 1.8.8-6 +- fix license handling + +* Sun Jun 08 2014 Fedora Release Engineering - 1.8.8-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Sat May 31 2014 Peter Robinson 1.8.8-4 +- Drop ChangeLog, we ship NEWS + +* Mon Mar 10 2014 Daniel Kopecek - 1.8.8-3 +- remove bundled copy of zlib before compilation +- drop the requiretty Defaults setting from sudoers + +* Sat Jan 25 2014 Ville Skyttä - 1.8.8-2 +- Own the %%{_libexecdir}/sudo dir. + +* Mon Sep 30 2013 Daniel Kopecek - 1.8.8-1 +- update to 1.8.8 +- major changes & fixes: + - LDAP SASL support now works properly with Kerberos + - root may no longer change its SELinux role without entering a password + - user messages are now always displayed in the user's locale, even when + the same message is being logged or mailed in a different locale. + - log files created by sudo now explicitly have the group set to group + ID 0 rather than relying on BSD group semantics + - sudo now stores its libexec files in a sudo subdirectory instead of in + libexec itself + - system_group and group_file sudoers group provider plugins are now + installed by default + - the paths to ldap.conf and ldap.secret may now be specified as arguments + to the sudoers plugin in the sudo.conf file + - ...and many new features and settings. See the upstream ChangeLog for the + full list. +- several sssd support fixes +- added patch to make uid/gid specification parsing more strict (don't accept + an invalid number as uid/gid) +- use the _pkgdocdir macro + (see https://fedoraproject.org/wiki/Changes/UnversionedDocdirs) +- fixed several bugs found by the clang static analyzer +- added %%post dependency on chmod + +* Sun Aug 04 2013 Fedora Release Engineering - 1.8.6p7-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Thu Feb 28 2013 Daniel Kopecek - 1.8.6p7-1 +- update to 1.8.6p7 +- fixes CVE-2013-1775 and CVE-2013-1776 +- fixed several packaging issues (thanks to ville.skytta@iki.fi) + - build with system zlib. + - let rpmbuild strip libexecdir/*.so. + - own the %%{_docdir}/sudo-* dir. + - fix some rpmlint warnings (spaces vs tabs, unescaped macros). + - fix bogus %%changelog dates. + +* Fri Feb 15 2013 Fedora Release Engineering - 1.8.6p3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Mon Nov 12 2012 Daniel Kopecek - 1.8.6p3-2 +- added upstream patch for a regression +- don't include arch specific files in the -devel subpackage +- ship only one sample plugin in the -devel subpackage + +* Tue Sep 25 2012 Daniel Kopecek - 1.8.6p3-1 +- update to 1.8.6p3 +- drop -pipelist patch (fixed in upstream) + +* Thu Sep 6 2012 Daniel Kopecek - 1.8.6-1 +- update to 1.8.6 + +* Thu Jul 26 2012 Daniel Kopecek - 1.8.5-4 +- added patches that fix & improve SSSD support (thanks to pbrezina@redhat.com) +- re-enabled SSSD support +- removed libsss_sudo dependency + +* Tue Jul 24 2012 Bill Nottingham - 1.8.5-3 +- flip sudoers2ldif executable bit after make install, not in setup + +* Sat Jul 21 2012 Fedora Release Engineering - 1.8.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Thu May 17 2012 Daniel Kopecek - 1.8.5-1 +- update to 1.8.5 +- fixed CVE-2012-2337 +- temporarily disabled SSSD support + +* Wed Feb 29 2012 Daniel Kopecek - 1.8.3p1-6 +- fixed problems with undefined symbols (rhbz#798517) + +* Wed Feb 22 2012 Daniel Kopecek - 1.8.3p1-5 +- SSSD patch update + +* Tue Feb 7 2012 Daniel Kopecek - 1.8.3p1-4 +- added SSSD support + +* Thu Jan 26 2012 Daniel Kopecek - 1.8.3p1-3 +- added patch for CVE-2012-0809 + +* Sat Jan 14 2012 Fedora Release Engineering - 1.8.3p1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Thu Nov 10 2011 Daniel Kopecek - 1.8.3p1-1 +- update to 1.8.3p1 +- disable output word wrapping if the output is piped + +* Wed Sep 7 2011 Peter Robinson - 1.8.1p2-2 +- Remove execute bit from sample script in docs so we don't pull in perl + +* Tue Jul 12 2011 Daniel Kopecek - 1.8.1p2-1 +- rebase to 1.8.1p2 +- removed .sudoi patch +- fixed typo: RELPRO -> RELRO +- added -devel subpackage for the sudo_plugin.h header file +- use default ldap configuration files again + +* Fri Jun 3 2011 Daniel Kopecek - 1.7.4p5-4 +- build with RELRO + +* Wed Feb 09 2011 Fedora Release Engineering - 1.7.4p5-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Jan 17 2011 Daniel Kopecek - 1.7.4p5-2 +- rebase to 1.7.4p5 +- fixed sudo-1.7.4p4-getgrouplist.patch +- fixes CVE-2011-0008, CVE-2011-0010 + +* Tue Nov 30 2010 Daniel Kopecek - 1.7.4p4-5 +- anybody in the wheel group has now root access (using password) (rhbz#656873) +- sync configuration paths with the nss_ldap package (rhbz#652687) + +* Wed Sep 29 2010 Daniel Kopecek - 1.7.4p4-4 +- added upstream patch to fix rhbz#638345 + +* Mon Sep 20 2010 Daniel Kopecek - 1.7.4p4-3 +- added patch for #635250 +- /var/run/sudo -> /var/db/sudo in .spec + +* Tue Sep 7 2010 Daniel Kopecek - 1.7.4p4-2 +- sudo now uses /var/db/sudo for timestamps + +* Tue Sep 7 2010 Daniel Kopecek - 1.7.4p4-1 +- update to new upstream version +- new command available: sudoreplay +- use native audit support +- corrected license field value: BSD -> ISC + +* Wed Jun 2 2010 Daniel Kopecek - 1.7.2p6-2 +- added patch that fixes insufficient environment sanitization issue (#598154) + +* Wed Apr 14 2010 Daniel Kopecek - 1.7.2p6-1 +- update to new upstream version +- merged .audit and .libaudit patch +- added sudoers.ldap.5* to files + +* Mon Mar 1 2010 Daniel Kopecek - 1.7.2p5-2 +- update to new upstream version + +* Tue Feb 16 2010 Daniel Kopecek - 1.7.2p2-5 +- fixed no valid sudoers sources found (#558875) + +* Wed Feb 10 2010 Daniel Kopecek - 1.7.2p2-4 +- audit related Makefile.in and configure.in corrections +- added --with-audit configure option +- removed call to libtoolize + +* Wed Feb 10 2010 Daniel Kopecek - 1.7.2p2-3 +- fixed segfault when #include directive is used in cycles (#561336) + +* Fri Jan 8 2010 Ville Skyttä - 1.7.2p2-2 +- Add /etc/sudoers.d dir and use it in default config (#551470). +- Drop *.pod man page duplicates from docs. + +* Thu Jan 07 2010 Daniel Kopecek - 1.7.2p2-1 +- new upstream version 1.7.2p2-1 +- commented out unused aliases in sudoers to make visudo happy (#550239) + +* Fri Aug 21 2009 Tomas Mraz - 1.7.1-7 +- rebuilt with new audit + +* Thu Aug 20 2009 Daniel Kopecek 1.7.1-6 +- moved secure_path from compile-time option to sudoers file (#517428) + +* Sun Jul 26 2009 Fedora Release Engineering - 1.7.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Thu Jul 09 2009 Daniel Kopecek 1.7.1-4 +- moved the closefrom() call before audit_help_open() (sudo-1.7.1-auditfix.patch) +- epoch number sync + +* Mon Jun 22 2009 Daniel Kopecek 1.7.1-1 +- updated sudo to version 1.7.1 +- fixed small bug in configure.in (sudo-1.7.1-conffix.patch) + +* Tue Feb 24 2009 Daniel Kopecek 1.6.9p17-6 +- fixed building with new libtool +- fix for incorrect handling of groups in Runas_User +- added /usr/local/sbin to secure-path + +* Tue Jan 13 2009 Daniel Kopecek 1.6.9p17-3 +- build with sendmail installed +- Added /usr/local/bin to secure-path + +* Tue Sep 02 2008 Peter Vrabec 1.6.9p17-2 +- adjust audit patch, do not scream when kernel is + compiled without audit netlink support (#401201) + +* Fri Jul 04 2008 Peter Vrabec 1.6.9p17-1 +- upgrade + +* Wed Jun 18 2008 Peter Vrabec 1.6.9p13-7 +- build with newer autoconf-2.62 (#449614) + +* Tue May 13 2008 Peter Vrabec 1.6.9p13-6 +- compiled with secure path (#80215) + +* Mon May 05 2008 Peter Vrabec 1.6.9p13-5 +- fix path to updatedb in /etc/sudoers (#445103) + +* Mon Mar 31 2008 Peter Vrabec 1.6.9p13-4 +- include ldap files in rpm package (#439506) + +* Thu Mar 13 2008 Peter Vrabec 1.6.9p13-3 +- include [sudo] in password prompt (#437092) + +* Tue Mar 04 2008 Peter Vrabec 1.6.9p13-2 +- audit support improvement + +* Thu Feb 21 2008 Peter Vrabec 1.6.9p13-1 +- upgrade to the latest upstream release + +* Wed Feb 06 2008 Peter Vrabec 1.6.9p12-1 +- upgrade to the latest upstream release +- add selinux support + +* Mon Feb 04 2008 Dennis Gilmore 1.6.9p4-6 +- sparc64 needs to be in the -fPIE list with s390 + +* Mon Jan 07 2008 Peter Vrabec 1.6.9p4-5 +- fix complains about audit_log_user_command(): Connection + refused (#401201) + +* Wed Dec 05 2007 Release Engineering - 1.6.9p4-4 +- Rebuild for deps + +* Wed Dec 05 2007 Release Engineering - 1.6.9p4-3 +- Rebuild for openssl bump + +* Thu Aug 30 2007 Peter Vrabec 1.6.9p4-2 +- fix autotools stuff and add audit support + +* Mon Aug 20 2007 Peter Vrabec 1.6.9p4-1 +- upgrade to upstream release + +* Thu Apr 12 2007 Peter Vrabec 1.6.8p12-14 +- also use getgrouplist() to determine group membership (#235915) + +* Mon Feb 26 2007 Peter Vrabec 1.6.8p12-13 +- fix some spec file issues + +* Thu Dec 14 2006 Peter Vrabec 1.6.8p12-12 +- fix rpmlint issue + +* Thu Oct 26 2006 Peter Vrabec 1.6.8p12-11 +- fix typo in sudoers file (#212308) + +* Sun Oct 01 2006 Jesse Keating - 1.6.8p12-10 +- rebuilt for unwind info generation, broken in gcc-4.1.1-21 + +* Thu Sep 21 2006 Peter Vrabec 1.6.8p12-9 +- fix sudoers file, X apps didn't work (#206320) + +* Tue Aug 08 2006 Peter Vrabec 1.6.8p12-8 +- use Red Hat specific default sudoers file + +* Sun Jul 16 2006 Karel Zak 1.6.8p12-7 +- fix #198755 - make login processes (sudo -i) initialise session keyring + (thanks for PAM config files to David Howells) +- add IPv6 support (patch by Milan Zazrivec) + +* Wed Jul 12 2006 Jesse Keating - 1.6.8p12-6.1 +- rebuild + +* Mon May 29 2006 Karel Zak 1.6.8p12-6 +- fix #190062 - "ssh localhost sudo su" will show the password in clear + +* Tue May 23 2006 Karel Zak 1.6.8p12-5 +- add LDAP support (#170848) + +* Fri Feb 10 2006 Jesse Keating - 1.6.8p12-4.1 +- bump again for double-long bug on ppc(64) + +* Wed Feb 8 2006 Karel Zak 1.6.8p12-4 +- reset env. by default + +* Tue Feb 07 2006 Jesse Keating - 1.6.8p12-3.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Mon Jan 23 2006 Dan Walsh 1.6.8p12-3 +- Remove selinux patch. It has been decided that the SELinux patch for sudo is +- no longer necessary. In tageted policy it had no effect. In strict/MLS policy +- We require the person using sudo to execute newrole before using sudo. + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Fri Nov 25 2005 Karel Zak 1.6.8p12-1 +- new upstream version 1.6.8p12 + +* Tue Nov 8 2005 Karel Zak 1.6.8p11-1 +- new upstream version 1.6.8p11 + +* Thu Oct 13 2005 Tomas Mraz 1.6.8p9-6 +- use include instead of pam_stack in pam config + +* Tue Oct 11 2005 Karel Zak 1.6.8p9-5 +- enable interfaces in selinux patch +- merge sudo-1.6.8p8-sesh-stopsig.patch to selinux patch + +* Mon Sep 19 2005 Karel Zak 1.6.8p9-4 +- fix debuginfo + +* Mon Sep 19 2005 Karel Zak 1.6.8p9-3 +- fix #162623 - sesh hangs when child suspends + +* Mon Aug 1 2005 Dan Walsh 1.6.8p9-2 +- Add back in interfaces call, SELinux has been fixed to work around + +* Tue Jun 21 2005 Karel Zak 1.6.8p9-1 +- new version 1.6.8p9 (resolve #161116 - CAN-2005-1993 sudo trusted user arbitrary command execution) + +* Tue May 24 2005 Karel Zak 1.6.8p8-2 +- fix #154511 - sudo does not use limits.conf + +* Mon Apr 4 2005 Thomas Woerner 1.6.8p8-1 +- new version 1.6.8p8: new sudoedit and sudo_noexec + +* Wed Feb 9 2005 Thomas Woerner 1.6.7p5-31 +- rebuild + +* Mon Oct 4 2004 Thomas Woerner 1.6.7p5-30.1 +- added missing BuildRequires for libselinux-devel (#132883) + +* Wed Sep 29 2004 Dan Walsh 1.6.7p5-30 +- Fix missing param error in sesh + +* Mon Sep 27 2004 Dan Walsh 1.6.7p5-29 +- Remove full patch check from sesh + +* Thu Jul 8 2004 Dan Walsh 1.6.7p5-28 +- Fix selinux patch to switch to root user + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Tue Apr 13 2004 Dan Walsh 1.6.7p5-26 +- Eliminate tty handling from selinux + +* Thu Apr 1 2004 Thomas Woerner 1.6.7p5-25 +- fixed spec file: sesh in file section with selinux flag (#119682) + +* Tue Mar 30 2004 Colin Walters 1.6.7p5-24 +- Enhance sesh.c to fork/exec children itself, to avoid + having sudo reap all domains. +- Only reinstall default signal handlers immediately before + exec of child with SELinux patch + +* Thu Mar 18 2004 Dan Walsh 1.6.7p5-23 +- change to default to sysadm_r +- Fix tty handling + +* Thu Mar 18 2004 Dan Walsh 1.6.7p5-22 +- Add /bin/sesh to run selinux code. +- replace /bin/bash -c with /bin/sesh + +* Tue Mar 16 2004 Dan Walsh 1.6.7p5-21 +- Hard code to use "/bin/bash -c" for selinux + +* Tue Mar 16 2004 Dan Walsh 1.6.7p5-20 +- Eliminate closing and reopening of terminals, to match su. + +* Mon Mar 15 2004 Dan Walsh 1.6.7p5-19 +- SELinux fixes to make transitions work properly + +* Fri Mar 5 2004 Thomas Woerner 1.6.7p5-18 +- pied sudo + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Tue Jan 27 2004 Dan Walsh 1.6.7p5-16 +- Eliminate interfaces call, since this requires big SELinux privs +- and it seems to be useless. + +* Tue Jan 27 2004 Karsten Hopp 1.6.7p5-15 +- visudo requires vim-minimal or setting EDITOR to something useful (#68605) + +* Mon Jan 26 2004 Dan Walsh 1.6.7p5-14 +- Fix is_selinux_enabled call + +* Tue Jan 13 2004 Dan Walsh 1.6.7p5-13 +- Clean up patch on failure + +* Tue Jan 6 2004 Dan Walsh 1.6.7p5-12 +- Remove sudo.te for now. + +* Fri Jan 2 2004 Dan Walsh 1.6.7p5-11 +- Fix usage message + +* Mon Dec 22 2003 Dan Walsh 1.6.7p5-10 +- Clean up sudo.te to not blow up if pam.te not present + +* Thu Dec 18 2003 Thomas Woerner +- added missing BuildRequires for groff + +* Tue Dec 16 2003 Jeremy Katz 1.6.7p5-9 +- remove left-over debugging code + +* Tue Dec 16 2003 Dan Walsh 1.6.7p5-8 +- Fix terminal handling that caused Sudo to exit on non selinux machines. + +* Mon Dec 15 2003 Dan Walsh 1.6.7p5-7 +- Remove sudo_var_run_t which is now pam_var_run_t + +* Fri Dec 12 2003 Dan Walsh 1.6.7p5-6 +- Fix terminal handling and policy + +* Thu Dec 11 2003 Dan Walsh 1.6.7p5-5 +- Fix policy + +* Thu Nov 13 2003 Dan Walsh 1.6.7p5-4.sel +- Turn on SELinux support + +* Tue Jul 29 2003 Dan Walsh 1.6.7p5-3 +- Add support for SELinux + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Mon May 19 2003 Thomas Woerner 1.6.7p5-1 + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Tue Nov 12 2002 Nalin Dahyabhai 1.6.6-2 +- remove absolute path names from the PAM configuration, ensuring that the + right modules get used for whichever arch we're built for +- don't try to install the FAQ, which isn't there any more + +* Thu Jun 27 2002 Bill Nottingham 1.6.6-1 +- update to 1.6.6 + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Thu May 23 2002 Tim Powers +- automated rebuild + +* Thu Apr 18 2002 Bernhard Rosenkraenzer 1.6.5p2-2 +- Fix bug #63768 + +* Thu Mar 14 2002 Bernhard Rosenkraenzer 1.6.5p2-1 +- 1.6.5p2 + +* Fri Jan 18 2002 Bernhard Rosenkraenzer 1.6.5p1-1 +- 1.6.5p1 +- Hope this "a new release per day" madness stops ;) + +* Thu Jan 17 2002 Bernhard Rosenkraenzer 1.6.5-1 +- 1.6.5 + +* Tue Jan 15 2002 Bernhard Rosenkraenzer 1.6.4p1-1 +- 1.6.4p1 + +* Mon Jan 14 2002 Bernhard Rosenkraenzer 1.6.4-1 +- Update to 1.6.4 + +* Mon Jul 23 2001 Bernhard Rosenkraenzer 1.6.3p7-2 +- Add build requirements (#49706) +- s/Copyright/License/ +- bzip2 source + +* Sat Jun 16 2001 Than Ngo +- update to 1.6.3p7 +- use %%{_tmppath} + +* Fri Feb 23 2001 Bernhard Rosenkraenzer +- 1.6.3p6, fixes buffer overrun + +* Tue Oct 10 2000 Bernhard Rosenkraenzer +- 1.6.3p5 + +* Wed Jul 12 2000 Prospector +- automatic rebuild + +* Tue Jun 06 2000 Karsten Hopp +- fixed owner of sudo and visudo + +* Thu Jun 1 2000 Nalin Dahyabhai +- modify PAM setup to use system-auth +- clean up buildrooting by using the makeinstall macro + +* Tue Apr 11 2000 Bernhard Rosenkraenzer +- initial build in main distrib +- update to 1.6.3 +- deal with compressed man pages + +* Tue Dec 14 1999 Preston Brown +- updated to 1.6.1 for Powertools 6.2 +- config files are now noreplace. + +* Thu Jul 22 1999 Tim Powers +- updated to 1.5.9p2 for Powertools 6.1 + +* Wed May 12 1999 Bill Nottingham +- sudo is configured with pam. There's no pam.d file. Oops. + +* Mon Apr 26 1999 Preston Brown +- upgraded to 1.59p1 for powertools 6.0 + +* Tue Oct 27 1998 Preston Brown +- fixed so it doesn't find /usr/bin/vi first, but instead /bin/vi (always installed) + +* Thu Oct 08 1998 Michael Maher +- built package for 5.2 + +* Mon May 18 1998 Michael Maher +- updated SPEC file + +* Thu Jan 29 1998 Otto Hammersmith +- updated to 1.5.4 + +* Tue Nov 18 1997 Otto Hammersmith +- built for glibc, no problems + +* Fri Apr 25 1997 Michael Fulbright +- Fixed for 4.2 PowerTools +- Still need to be pamified +- Still need to move stmp file to /var/log + +* Mon Feb 17 1997 Michael Fulbright +- First version for PowerCD. diff --git a/sudoers b/sudoers new file mode 100644 index 0000000..5f621a8 --- /dev/null +++ b/sudoers @@ -0,0 +1,120 @@ +## Sudoers allows particular users to run various commands as +## the root user, without needing the root password. +## +## Examples are provided at the bottom of the file for collections +## of related commands, which can then be delegated out to particular +## users or groups. +## +## This file must be edited with the 'visudo' command. + +## Host Aliases +## Groups of machines. You may prefer to use hostnames (perhaps using +## wildcards for entire domains) or IP addresses instead. +# Host_Alias FILESERVERS = fs1, fs2 +# Host_Alias MAILSERVERS = smtp, smtp2 + +## User Aliases +## These aren't often necessary, as you can use regular groups +## (ie, from files, LDAP, NIS, etc) in this file - just use %groupname +## rather than USERALIAS +# User_Alias ADMINS = jsmith, mikem + + +## Command Aliases +## These are groups of related commands... + +## Networking +# Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /usr/bin/net, /sbin/iptables, /usr/bin/rfcomm, /usr/bin/wvdial, /sbin/iwconfig, /sbin/mii-tool + +## Installation and management of software +# Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum + +## Services +# Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig, /usr/bin/systemctl start, /usr/bin/systemctl stop, /usr/bin/systemctl reload, /usr/bin/systemctl restart, /usr/bin/systemctl status, /usr/bin/systemctl enable, /usr/bin/systemctl disable + +## Updating the locate database +# Cmnd_Alias LOCATE = /usr/bin/updatedb + +## Storage +# Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, /sbin/partprobe, /bin/mount, /bin/umount + +## Delegating permissions +# Cmnd_Alias DELEGATING = /usr/sbin/visudo, /bin/chown, /bin/chmod, /bin/chgrp + +## Processes +# Cmnd_Alias PROCESSES = /bin/nice, /bin/kill, /usr/bin/kill, /usr/bin/killall + +## Drivers +# Cmnd_Alias DRIVERS = /sbin/modprobe + +# Defaults specification + +# +# Refuse to run if unable to disable echo on the tty. +# +Defaults !visiblepw + +# +# Preserving HOME has security implications since many programs +# use it when searching for configuration files. Note that HOME +# is already set when the the env_reset option is enabled, so +# this option is only effective for configurations where either +# env_reset is disabled or HOME is present in the env_keep list. +# +Defaults always_set_home +Defaults match_group_by_gid + +# Prior to version 1.8.15, groups listed in sudoers that were not +# found in the system group database were passed to the group +# plugin, if any. Starting with 1.8.15, only groups of the form +# %:group are resolved via the group plugin by default. +# We enable always_query_group_plugin to restore old behavior. +# Disable this option for new behavior. +Defaults always_query_group_plugin + +Defaults env_reset +Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS" +Defaults env_keep += "MAIL QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE" +Defaults env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES" +Defaults env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE" +Defaults env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY" + +# +# Adding HOME to env_keep may enable a user to run unrestricted +# commands via sudo. +# +# Defaults env_keep += "HOME" + +Defaults secure_path = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/lib/snapd/snap/bin + +## Next comes the main part: which users can run what software on +## which machines (the sudoers file can be shared between multiple +## systems). +## Syntax: +## +## user MACHINE=COMMANDS +## +## The COMMANDS section may have other options added to it. +## +## Allow root to run any commands anywhere +root ALL=(ALL) ALL + +## Allows members of the 'sys' group to run networking, software, +## service management apps and more. +# %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS + +## Allows people in group wheel to run all commands +%wheel ALL=(ALL) ALL + +## Same thing without a password +# %wheel ALL=(ALL) NOPASSWD: ALL + +## Allows members of the users group to mount and unmount the +## cdrom as root +# %users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom + +## Allows members of the users group to shutdown this system +# %users localhost=/sbin/shutdown -h now + +## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment) +#includedir /etc/sudoers.d diff --git a/tests/fully-qualified-hostnames/Makefile b/tests/fully-qualified-hostnames/Makefile new file mode 100644 index 0000000..101e635 --- /dev/null +++ b/tests/fully-qualified-hostnames/Makefile @@ -0,0 +1,71 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /CoreOS/sudo/Sanity/fully-qualified-hostnames +# Description: checks if sudo works correctly when FQDN is used in /etc/sudoers +# Author: Milos Malik +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2011 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/CoreOS/sudo/Sanity/fully-qualified-hostnames +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) runtest.sh Makefile PURPOSE ssh-sudo.exp + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + chmod a+x runtest.sh + chmod a+x ssh-sudo.exp + +clean: + rm -f *~ $(BUILT_FILES) + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Milos Malik " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: checks if sudo works correctly when FQDN is used in /etc/sudoers" >> $(METADATA) + @echo "Type: Sanity" >> $(METADATA) + @echo "TestTime: 10m" >> $(METADATA) + @echo "RunFor: sudo" >> $(METADATA) + @echo "Requires: sudo" >> $(METADATA) + @echo "Requires: sed" >> $(METADATA) + @echo "Requires: grep" >> $(METADATA) + @echo "Requires: mktemp" >> $(METADATA) + @echo "Requires: openssh-server" >> $(METADATA) + @echo "Requires: openssh-clients" >> $(METADATA) + @echo "Requires: expect" >> $(METADATA) + @echo "Requires: shadow-utils" >> $(METADATA) + @echo "Priority: Normal" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + @echo "Confidential: no" >> $(METADATA) + @echo "Destructive: no" >> $(METADATA) + + rhts-lint $(METADATA) + diff --git a/tests/fully-qualified-hostnames/PURPOSE b/tests/fully-qualified-hostnames/PURPOSE new file mode 100644 index 0000000..c27b508 --- /dev/null +++ b/tests/fully-qualified-hostnames/PURPOSE @@ -0,0 +1,3 @@ +PURPOSE of /CoreOS/sudo/Sanity/fully-qualified-hostnames +Description: checks if sudo works correctly when FQDN is used in /etc/sudoers +Author: Milos Malik diff --git a/tests/fully-qualified-hostnames/runtest.sh b/tests/fully-qualified-hostnames/runtest.sh new file mode 100755 index 0000000..db3a893 --- /dev/null +++ b/tests/fully-qualified-hostnames/runtest.sh @@ -0,0 +1,106 @@ +#!/bin/bash +# vim: dict=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# runtest.sh of /CoreOS/sudo/Sanity/fully-qualified-hostnames +# Description: checks if sudo works correctly when FQDN is used in /etc/sudoers +# Author: Milos Malik +# Edit: Ales "alich" Marecek +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2011 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include rhts environment +. /usr/bin/rhts-environment.sh +. /usr/share/beakerlib/beakerlib.sh + +PACKAGE="sudo" +USER_NAME="user${RANDOM}" +USER_SECRET="s3kr3T${RANDOM}" +CONFIG_FILE="/etc/sudoers" +OUTPUT_FILE="sudo.log" + +rlJournalStart + rlPhaseStartSetup + rlAssertRpm ${PACKAGE} + rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory" + rlRun "cp ssh-sudo.exp ${TmpDir}" 0 "Copying expect file" + rlRun "pushd $TmpDir" + OUTPUT_FILE="${TmpDir}/${OUTPUT_FILE}" + rlFileBackup ${CONFIG_FILE} ~/.ssh + id ${USER_NAME} && userdel -r ${USER_NAME} + rlRun "useradd ${USER_NAME}" + rlRun "echo ${USER_SECRET} | passwd --stdin ${USER_NAME}" + rlRun "sed -i 's/^.*requiretty.*$//' ${CONFIG_FILE}" + rlRun "sed -i 's/^.*lecture.*$//' ${CONFIG_FILE}" + rlRun "echo \"Defaults !requiretty, !lecture\" >> ${CONFIG_FILE}" + rlRun "echo \"${USER_NAME} ${HOSTNAME} = (root) `which id`\" >> ${CONFIG_FILE}" + rlRun "> ~/.ssh/known_hosts" + rlPhaseEnd + + if rlIsRHEL 5; then + rlPhaseStartTest + rlRun "strings `which sudo` | grep fqdn" + rlPhaseEnd + fi + + if echo ${HOSTNAME} | grep -q '^localhost'; then + rlPhaseStartTest + rlLogInfo "skipping fqdn option enabled tests, cannot run with local-only host name ${HOSTNAME}" + rlPhaseEnd + else + rlPhaseStartTest "fqdn option is enabled, command is valid" + rlRun "sed -i 's/^.*fqdn.*$//' ${CONFIG_FILE}" + rlRun "echo \"Defaults fqdn\" >> ${CONFIG_FILE}" + rlRun "./ssh-sudo.exp ${USER_NAME} ${USER_SECRET} localhost id 2>&1 | tee ${OUTPUT_FILE}" + rlAssertGrep "uid=0.*gid=0.*groups=0" ${OUTPUT_FILE} + rlPhaseEnd + + rlPhaseStartTest "fqdn option is enabled, command is invalid" + rlRun "sed -i 's/^.*fqdn.*$//' ${CONFIG_FILE}" + rlRun "echo \"Defaults fqdn\" >> ${CONFIG_FILE}" + rlRun "./ssh-sudo.exp ${USER_NAME} ${USER_SECRET} localhost w 2>&1 | tee ${OUTPUT_FILE}" + rlAssertGrep "user.*is not allowed to execute" ${OUTPUT_FILE} + rlPhaseEnd + fi + + rlPhaseStartTest "fqdn option is disabled, command is valid" + rlRun "sed -i 's/^.*fqdn.*$//' ${CONFIG_FILE}" + rlRun "echo \"Defaults !fqdn\" >> ${CONFIG_FILE}" + rlRun "./ssh-sudo.exp ${USER_NAME} ${USER_SECRET} localhost id 2>&1 | tee ${OUTPUT_FILE}" + rlAssertGrep "uid=0.*gid=0.*groups=0" ${OUTPUT_FILE} + rlPhaseEnd + + rlPhaseStartTest "fqdn option is disabled, command is invalid" + rlRun "sed -i 's/^.*fqdn.*$//' ${CONFIG_FILE}" + rlRun "echo \"Defaults !fqdn\" >> ${CONFIG_FILE}" + rlRun "./ssh-sudo.exp ${USER_NAME} ${USER_SECRET} localhost w 2>&1 | tee ${OUTPUT_FILE}" + rlAssertGrep "user.*is not allowed to execute" ${OUTPUT_FILE} + rlPhaseEnd + + rlPhaseStartCleanup + rlRun "userdel -rf ${USER_NAME}" + rlFileRestore + rlRun "popd" + rlRun "rm -r $TmpDir" 0 "Removing tmp directory" + rlPhaseEnd +rlJournalPrintText +rlJournalEnd + diff --git a/tests/fully-qualified-hostnames/ssh-sudo.exp b/tests/fully-qualified-hostnames/ssh-sudo.exp new file mode 100755 index 0000000..44863e4 --- /dev/null +++ b/tests/fully-qualified-hostnames/ssh-sudo.exp @@ -0,0 +1,20 @@ +#!/usr/bin/expect -f +# usage: +# ./ssh-sudo.exp username password hostname command +set username [lrange $argv 0 0] +set password [lrange $argv 1 1] +set hostname [lrange $argv 2 2] +set command [lrange $argv 3 3] +set timeout 5 +spawn ssh -t $username@$hostname sudo $command +expect "*yes/no*" { + send -- "yes\r" +} +expect "*assword*" { + send -- "$password\r" +} +expect "*assword*" { + send -- "$password\r" +} +expect eof + diff --git a/tests/run-as/Makefile b/tests/run-as/Makefile new file mode 100644 index 0000000..411464b --- /dev/null +++ b/tests/run-as/Makefile @@ -0,0 +1,68 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /CoreOS/sudo/Sanity/run-as +# Description: Test feature 'run as'. This means -u, -g options. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2017 Red Hat, Inc. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/CoreOS/sudo/Sanity/run-as +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) runtest.sh Makefile PURPOSE + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Test feature 'run as'. This means -u, -g options." >> $(METADATA) + @echo "Type: Sanity" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RunFor: sudo" >> $(METADATA) + @echo "Requires: sudo" >> $(METADATA) + @echo "RhtsRequires: library(distribution/tcf)" >> $(METADATA) + @echo "RhtsRequires: library(distribution/Cleanup)" >> $(METADATA) + @echo "RhtsRequires: library(distribution/testUser)" >> $(METADATA) + @echo "RhtsRequires: library(distribution/ConditionalPhases)" >> $(METADATA) + @echo "Priority: Normal" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + @echo "Confidential: no" >> $(METADATA) + @echo "Destructive: no" >> $(METADATA) + @echo "Releases: -RHEL4 -RHELClient5 -RHELServer5" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/run-as/PURPOSE b/tests/run-as/PURPOSE new file mode 100644 index 0000000..387bc5b --- /dev/null +++ b/tests/run-as/PURPOSE @@ -0,0 +1,3 @@ +PURPOSE of /CoreOS/sudo/Sanity/run-as +Description: Test feature 'run as'. This means -u, -g options. +Author: Dalibor Pospisil diff --git a/tests/run-as/distribution/Library/Cleanup/Makefile b/tests/run-as/distribution/Library/Cleanup/Makefile new file mode 100644 index 0000000..3e5a8e1 --- /dev/null +++ b/tests/run-as/distribution/Library/Cleanup/Makefile @@ -0,0 +1,59 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /distribution/Library/Cleanup +# Description: Block style coding with ability of skipping parts. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/distribution/Library/Cleanup +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) lib.sh Makefile + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Provides function to define cleanup stack which can do its work at any time of the test run." >> $(METADATA) + @echo "Type: Library" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "Provides: library(distribution/Cleanup)" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/run-as/distribution/Library/Cleanup/lib.sh b/tests/run-as/distribution/Library/Cleanup/lib.sh new file mode 100644 index 0000000..c66d21c --- /dev/null +++ b/tests/run-as/distribution/Library/Cleanup/lib.sh @@ -0,0 +1,314 @@ +#!/bin/bash +# Authors: Dalibor Pospíšil +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# library-prefix = Cleanup +# library-version = 9 +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +__INTERNAL_Cleanup_LIB_VERSION=9 +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib library Cleanup + +=head1 DESCRIPTION + +This file contains functions which provides cleanup stack functionality. + +=head1 USAGE + +To use this functionality you need to import library distribution/Cleanup and add +following line to Makefile. + + @echo "RhtsRequires: library(distribution/Cleanup)" >> $(METADATA) + +B + + rlJournalStart + rlPhaseStartSetup + rlImport 'distribution/Cleanup' + tmp=$(mktemp) + CleanupRegister " + rlLog 'Removing data' + rlRun \"rm -f ${tmp}\" + " + rlLog 'Creating some data' + rlRun "echo 'asdfalkjh' > $tmp" + + CleanupRegister " + rlLog 'just something to demonstrate unregistering' + " + ID1=$CleanupRegisterID + CleanupUnregister $ID1 + + CleanupRegister " + rlLog 'just something to demonstrate partial cleanup' + " + ID2=$CleanupRegisterID + CleanupRegister "rlLog 'cleanup some more things'" + # cleanup everything upto ID2 + CleanupDo $ID2 + + CleanupRegister --mark " + rlLog 'yet another something to demonstrate partial cleanup using internal ID saving' + " + CleanupRegister "rlLog 'cleanup some more things'" + # cleanup everything upto last mark + CleanupDo --mark + rlPhaseEnd + + rlPhaseStartCleanup + CleanupDo + rlPhaseEnd + + rlJournalPrintText + rlJournalEnd + +=head1 FUNCTIONS + +=cut + +echo -n "loading library Cleanup v$__INTERNAL_Cleanup_LIB_VERSION... " + +__INTERNAL_Cleanup_stack_file="$BEAKERLIB_DIR/Cleanup_stack" +touch "$__INTERNAL_Cleanup_stack_file" +chmod ug+rw "$__INTERNAL_Cleanup_stack_file" + +# CleanupRegister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# CleanupRegister [--mark] CLEANUP_CODE +# --mark - also mark this position +CleanupRegister() { + local mark=0 + [[ "$1" == "--mark" ]] && { + mark=1 + shift + } + if ! CleanupGetStack; then + rlLogError "cannot continue, could not get cleanup stack" + return 1 + fi + CleanupRegisterID="${RANDOM}$(date +"%s%N")" + echo -n "Registering cleanup ID=$CleanupRegisterID" >&2 + if [[ $mark -eq 1 ]]; then + __INTERNAL_CleanupMark=( "$CleanupRegisterID" "${__INTERNAL_CleanupMark[@]}" ) + echo -n " with mark" >&2 + fi + echo " '$1'" >&2 + rlLogDebug "prepending '$1'" + local ID_tag="# ID='$CleanupRegisterID'" + __INTERNAL_Cleanup_stack="$ID_tag +$1 +$ID_tag +$__INTERNAL_Cleanup_stack" + if ! CleanupSetStack "$__INTERNAL_Cleanup_stack"; then + rlLogError "an error occured while registering the cleanup '$1'" + return 1 + fi + return 0 +}; # end of CleanupRegister }}} + + +# __INTERNAL_Cleanup_get_stack_part ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# 1: ID +# -ID - everything upto the ID +# 2: '' - return ID only +# 'rest' - return exact oposit +__INTERNAL_Cleanup_get_stack_part() { + rlLogDebug "__INTERNAL_Cleanup_get_stack_part(): $* begin" + local ID="$1" + local n='1 0 1' + local stack='' + [[ "${ID:0:1}" == "-" ]] && { + ID="${ID:1}" + n='0 0 1' + } + [[ "$2" == "rest" ]] && { + n="$(echo "${n//0/2}")" + n="$(echo "${n//1/0}")" + n="$(echo "${n//2/1}")" + } + n=($n) + [[ -n "$DEBUG" ]] && rlLogDebug "$(set | grep ^n=)" + local ID_tag="# ID='$ID'" + while IFS= read -r line; do + + [[ "$line" == "$ID_tag" ]] && { + n=( "${n[@]:1}" ) + continue + } + if [[ $n -eq 0 ]]; then + stack="$stack +$line" + fi + done < <(echo "$__INTERNAL_Cleanup_stack") + rlLogDebug "__INTERNAL_Cleanup_get_stack_part(): cleanup stack part is '${stack:1}'" + echo "${stack:1}" + rlLogDebug "__INTERNAL_Cleanup_get_stack_part(): $* end" +}; # end of __INTERNAL_Cleanup_get_stack_part }}} + +# CleanupUnregister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +CleanupUnregister() { + local ID="$1" + rlLog "Unregistering cleanup ID='$ID'" + if ! CleanupGetStack; then + rlLogError "cannot continue, could not get cleanup stack" + return 1 + fi + rlLogDebug "removing ID='$ID'" + if ! CleanupSetStack "$(__INTERNAL_Cleanup_get_stack_part "$ID" 'rest')"; then + rlLogError "an error occured while registering the cleanup '$1'" + return 1 + fi + return 0 +}; # end of CleanupUnregister }}} + + +# CleanupMark ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_CleanupMark=() +CleanupMark() { + echo -n "Setting cleanup mark" >&2 + CleanupRegister --mark '' 2>/dev/null + local res=$? + echo " ID='$CleanupRegisterID'" >&2 + return $res +}; # end of CleanupMark }}} + + +# CleanupDo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# 1: '' - cleanup all +# ID - cleanup ID only +# -ID - cleanup all upto ID, including +# mark - cleanup all unto last mark, including +CleanupDo() { + local ID="$1" + if ! CleanupGetStack; then + rlLogError "cannot continue, could not get cleanup stack" + return 1 + fi + local res tmp newstack='' + tmp="$(mktemp)" + if [[ "$ID" == "mark" || "$ID" == "--mark" ]]; then + echo "execute cleanup upto mark='$__INTERNAL_CleanupMark'" >&2 + __INTERNAL_Cleanup_get_stack_part "-$__INTERNAL_CleanupMark" | grep -v "^# ID='" > "$tmp" + newstack="$(__INTERNAL_Cleanup_get_stack_part "-$__INTERNAL_CleanupMark" 'rest')" + __INTERNAL_CleanupMark=("${__INTERNAL_CleanupMark[@]:1}") + elif [[ -n "$ID" ]]; then + echo "execute cleanup for ID='$ID'" >&2 + __INTERNAL_Cleanup_get_stack_part "$ID" | grep -v "^# ID='" > "$tmp" + newstack="$(__INTERNAL_Cleanup_get_stack_part "$ID" 'rest')" + else + CleanupTrapUnhook + trap "echo 'temporarily blocking ctrl+c until cleanup is done' >&2" SIGINT + cat "$__INTERNAL_Cleanup_stack_file" | grep -v "^# ID='" > "$tmp" + echo "execute whole cleanup stack" >&2 + fi + . "$tmp" + res=$? + [[ $res -ne 0 ]] && { + echo "cleanup code:" >&2 + cat -n "$tmp" >&2 + } + rm -f "$tmp" + echo "cleanup execution done" >&2 + if [[ -z "$ID" ]]; then + trap - SIGINT + fi + if ! CleanupSetStack "$newstack"; then + rlLogError "an error occured while cleaning the stack" + return 1 + fi + return $res +}; # end of CleanupDo }}} + + +# CleanupGetStack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +CleanupGetStack() { + rlLogDebug "getting cleanup stack" + if [[ -r "$__INTERNAL_Cleanup_stack_file" ]]; then + if __INTERNAL_Cleanup_stack="$(cat "$__INTERNAL_Cleanup_stack_file")"; then + rlLogDebug "cleanup stack is '$__INTERNAL_Cleanup_stack'" + return 0 + fi + fi + rlLogError "could not load cleanup stack" + return 1 +}; # end of CleanupGetStack }}} + + +# CleanupSetStack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +CleanupSetStack() { + rlLogDebug "setting cleanup stack to '$1'" + __INTERNAL_Cleanup_stack="$1" + if echo "$__INTERNAL_Cleanup_stack" > "$__INTERNAL_Cleanup_stack_file"; then + rlLogDebug "cleanup stack is now '$__INTERNAL_Cleanup_stack'" + return 0 + fi + rlLogError "could not set cleanup stack" + return 1 +}; # end of CleanupSetStack }}} + + +__INTERNAL_Cleanup_signals='' +__INTERNAL_Cleanup_trap_code='rlJournalStart; rlPhaseStartCleanup; CleanupDo; rlPhaseEnd; rlJournalPrintText; rlJournalEnd; exit' +# CleanupTrapHook ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +CleanupTrapHook() { + rlLog "register cleanup trap" + __INTERNAL_Cleanup_signals="${1:-"SIGHUP SIGINT SIGTERM EXIT"}" + eval "trap \"${__INTERNAL_Cleanup_trap_code}\" $__INTERNAL_Cleanup_signals" +}; # end of CleanupTrapHook }}} + + +# CleanupTrapUnhook ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +CleanupTrapUnhook() { + if [[ -n "$__INTERNAL_Cleanup_signals" ]]; then + rlLog "unregister cleanup trap" + eval trap - $__INTERNAL_Cleanup_signals + __INTERNAL_Cleanup_signals='' + fi +}; # end of CleanupTrapUnhook }}} + + +# CleanupLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +CleanupLibraryLoaded() { + CleanupTrapHook +}; # end of CleanupLibraryLoaded }}} + + +echo "done." + +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Dalibor Pospisil + +=back + +=cut + diff --git a/tests/run-as/distribution/Library/ConditionalPhases/Makefile b/tests/run-as/distribution/Library/ConditionalPhases/Makefile new file mode 100644 index 0000000..f017bcb --- /dev/null +++ b/tests/run-as/distribution/Library/ConditionalPhases/Makefile @@ -0,0 +1,59 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /distribution/Library/ConditionalPhases +# Description: Implements conditional phases. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/distribution/Library/ConditionalPhases +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) lib.sh Makefile + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Implements conditional phases." >> $(METADATA) + @echo "Type: Library" >> $(METADATA) + @echo "Provides: library(distribution/ConditionalPhases)" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/run-as/distribution/Library/ConditionalPhases/lib.sh b/tests/run-as/distribution/Library/ConditionalPhases/lib.sh new file mode 100644 index 0000000..39024d1 --- /dev/null +++ b/tests/run-as/distribution/Library/ConditionalPhases/lib.sh @@ -0,0 +1,166 @@ +#!/bin/bash +# Authors: Dalibor Pospíšil +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# library-prefix = ConditionalPhases +# library-version = 2 +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +__INTERNAL_ConditionalPhases_LIB_VERSION=2 +__INTERNAL_ConditionalPhases_LIB_NAME='distribution/ConditionalPhases' +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib library distribution/condpahses + +=head1 DESCRIPTION + +Implements conditional phases to eficiently select test phases to be execute +using white and black lists. + +To use this functionality you need to import library +distribution/ConditionalPhases and add following line to Makefile. + + @echo "RhtsRequires: library(distribution/ConditionalPhases)" >> $(METADATA) + +=head1 USAGE + +=head2 Conditional phases + +Each test phase can be conditionally skipped based on a bash regular expression +given in CONDITIONAL_PHASES_BL and/or CONDITIONAL_PHASES_WL variables. + +=over + +=item CONDITIONAL_PHASES_BL + +It is a black list. If match phase name the respective phase should be skipped. + +=item CONDITIONAL_PHASES_WL + +It is a white list. If does B match phase name the respective phase should +be skipped excluding phases contatning 'setup' or 'cleanup' in its name. Names +'setup' and 'cleanup' are matched case insenitively. + +=back + +Actual skipping has to be done in the test case itself by using return code of +functions I, I, I, and +I. + +Example: + + rlPhaseStartTest "phase name" && { + ... + rlPhaseEnd; } + +Evaluation of the phase relevancy works as follows: + 1. If CONDITIONAL_PHASES_BL is non-empty and matches phase name => return 2. + 2. If phase name contains word 'setup' or 'cleanup' or CONDITIONAL_PHASES_WL + is empty => return 0. + 3. If CONDITIONAL_PHASES_WL is non-empty and matches phase name => return 0 + otherwise return 1. + +Normaly Setup and Cleanup phases are not skipped unless hey are B +black-listed. + +To make the test work properly with conditional phases it is necessary to +surround phase code with curly brackets and make it conditionally executed +based on rlPhaseStart* function's exit code the same way as it is demostrated in +the example above. To make the process easy you can use following command: + + sed 's/rlPhaseStart[^{]*$/& \&\& {/;s/rlPhaseEnd[^}]*$/&; }/' + +This code can be embedded in Makefile by modifying build target to following +form: + + build: $(BUILT_FILES) + grep -Eq 'rlPhase(Start[^{]*|End[^}]*)$' runtest.sh && sed -i 's/rlPhaseStart[^{]*$/& \&\& {/;s/rlPhaseEnd[^}]*$/&; }/' testrun.sh + test -x runtest.sh || chmod a+x runtest.sh + + +=cut +#' +echo -n "loading library $__INTERNAL_ConditionalPhases_LIB_NAME v$__INTERNAL_ConditionalPhases_LIB_VERSION... " + + +# ConditionalPhasesLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +ConditionalPhasesLibraryLoaded() { + if [[ -n "$CONDITIONAL_PHASES_BL" || -n "$CONDITIONAL_PHASES_WL" ]]; then + __INTERNAL_ConditionalPhases_eval() { + # check phases black-list + [[ -n "$CONDITIONAL_PHASES_BL" && "$1" =~ $CONDITIONAL_PHASES_BL ]] && { + rlLogWarning "phase '$1' should be skipped as it is defined in \$CONDITIONAL_PHASES_BL='$CONDITIONAL_PHASES_BL'" + return 2 + } + # always execute Setup, Cleanup and if no PHASES (white-list) specified + [[ "$1" =~ $(echo "\<[Ss][Ee][Tt][Uu][Pp]\>") || "$1" =~ $(echo "\<[Cc][Ll][Ee][Aa][Nn][Uu][Pp]\>") ]] && { + rlLogInfo "phase '$1' will be executed as 'setup' and 'cleanup' phases are allowed by default, these can be black-listed" + return 0 + } + [[ -z "$CONDITIONAL_PHASES_WL" ]] && { + rlLogInfo "phase '$1' will be executed as there is no rule for it" + return 0 + } + [[ "$1" =~ $CONDITIONAL_PHASES_WL ]] && { + rlLogInfo "phase '$1' will be executed as it is defined in \$CONDITIONAL_PHASES_WL='$CONDITIONAL_PHASES_WL'" + return 0 + } || { + rlLogWarning "phase '$1' should be skipped as it is not defined in \$CONDITIONAL_PHASES_WL='$CONDITIONAL_PHASES_WL'" + return 1 + } + } + + rlLogInfo "replacing rlPhaseStart by modified function with conditional phases implemented" + :; rlPhaseStart() { + if [ "x$1" = "xFAIL" -o "x$1" = "xWARN" ] ; then + __INTERNAL_ConditionalPhases_eval "$2" && \ + rljAddPhase "$1" "$2" + return $? + else + rlLogError "rlPhaseStart: Unknown phase type: $1" + return 1 + fi + } + else + rlLogInfo "Neither CONDITIONAL_PHASES_WL nor CONDITIONAL_PHASES_BL is defined, not applying modifications" + fi +}; # end of ConditionalPhasesLibraryLoaded }}} + + +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Dalibor Pospisil + +=back + +=cut + +echo 'done.' diff --git a/tests/run-as/distribution/Library/Log/Makefile b/tests/run-as/distribution/Library/Log/Makefile new file mode 100644 index 0000000..3cf0e65 --- /dev/null +++ b/tests/run-as/distribution/Library/Log/Makefile @@ -0,0 +1,48 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /distribution/Library/Log +# Description: Block style coding with ability of skipping parts. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/distribution/Library/Log +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) lib.sh Makefile + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Provides yet another logging facility that does not rely on beakerlib while it can integrate with it." >> $(METADATA) + @echo "Type: Library" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RhtsRequires: library(distribution/opts)" >> $(METADATA) + @echo "Provides: library(distribution/Log)" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/run-as/distribution/Library/Log/lib.sh b/tests/run-as/distribution/Library/Log/lib.sh new file mode 100644 index 0000000..ac1db3d --- /dev/null +++ b/tests/run-as/distribution/Library/Log/lib.sh @@ -0,0 +1,637 @@ +#!/bin/bash +# Authors: Dalibor Pospíšil +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2013 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# library-prefix = Log +# library-version = 11 +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +__INTERNAL_Log_LIB_VERSION=11 +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib library Log + +=head1 DESCRIPTION + +This library provide logging capability which does not rely on beakerlib so it +can be used standalone. + +If it is used within beakerlib it automatically bypass all messages to the +beakerlib. + +Also this library provide journaling feature so the summary can be printed out +at the end. + +=head1 USAGE + +To use this functionality you need to import library distribution/Log and add +following line to Makefile. + + @echo "RhtsRequires: library(distribution/Log)" >> $(METADATA) + +=head1 FUNCTIONS + +=cut + +echo -n "loading library Log v$__INTERNAL_Log_LIB_VERSION... " + + +__INTERNAL_Log_prefix='' +__INTERNAL_Log_prefix2='' +__INTERNAL_Log_postfix='' +__INTERNAL_Log_default_level=3 +__INTERNAL_Log_level=$__INTERNAL_Log_default_level +LogSetDebugLevel() { + if [[ -n "$1" ]]; then + if [[ "$1" =~ ^[0-9]+$ ]]; then + let __INTERNAL_Log_level=$__INTERNAL_Log_default_level+$1; + else + __INTERNAL_Log_level=255 + fi + else + __INTERNAL_Log_level=$__INTERNAL_Log_default_level + fi +} +LogSetDebugLevel "$DEBUG" +let __INTERNAL_Log_level_LOG=0 +let __INTERNAL_Log_level_FATAL=0 +let __INTERNAL_Log_level_ERROR=1 +let __INTERNAL_Log_level_WARNING=2 +let __INTERNAL_Log_level_INFO=3 +let __INTERNAL_Log_level_DEBUG=4 +let __INTERNAL_Log_level_MORE=5 +let __INTERNAL_Log_level_MORE_=$__INTERNAL_Log_level_MORE+1 +let __INTERNAL_Log_level_MORE__=$__INTERNAL_Log_level_MORE_+1 +let __INTERNAL_Log_level_MORE___=$__INTERNAL_Log_level_MORE__+1 + +# Log ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +Log() { + LogMore___ -f "begin '$*'" + local pri=$2 message="${__INTERNAL_Log_prefix}${__INTERNAL_Log_prefix2}${1}${__INTERNAL_Log_postfix}" + if [[ -n "$pri" ]]; then + LogPrintMessage "$pri" "$message" + LogjAddMessage "$pri" "$message" + else + LogPrintMessage "$(date +%H:%M:%S)" "$message" + LogjAddMessage "INFO" "$message" + fi + LogMore___ -f "end" + return 0 +}; # end of Log }}} + + +__INTERNAL_Log_condition() { + cat <&2 + return 0 +}; # end of LogPrintMessage }}} + + +# LogReport ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 LogReport + +Prints final report similar to breakerlib's rlJournalPrintText. This is useful +mainly if you use TCF without beakerlib. + + LogReport + +=cut +#' + +LogReport() { + echo -e "\n ====== Summary report begin ======" + local a p l i + for i in $(seq 0 2 $((${#__INTERNAL_Log_journal[@]}-1)) ); do + LogPrintMessage "${__INTERNAL_Log_journal[$i]}" "${__INTERNAL_Log_journal[$((++i))]}" + done + echo " ======= Summary report end =======" + __INTERNAL_Log_journal=() +}; # end of LogReport }}} + + +# LogFile ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +LogFile() { + LogMore__ -f "begin '$*'" + local prio='' + [[ $# -ge 3 ]] && { + optsBegin + optsAdd 'prio|tag|p|t' --mandatory + optsDone; eval "${optsCode}" + } + cat $1 | while IFS= read line; do + Log "$line" "${prio:-$2}" + done + LogMore__ -f "end" +}; #}}} + + +# LogText ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +LogText() { + LogMore__ -f "begin '$*'" + local prio='' + [[ $# -ge 3 ]] && { + optsBegin + optsAdd 'prio|tag|p|t' --mandatory + optsDone; eval "${optsCode}" + } + { + if [[ "$1" == "-" ]]; then + cat - + else + echo "$1" + fi + } | while IFS= read line; do + Log "$line" "${prio:-$2}" + done + LogMore__ -f "end" +}; #}}} + + +# LogStrippedDiff ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +LogStrippedDiff() { + LogMore__ -f "begin '$*'" + local prio='' + [[ $# -ge 3 ]] && { + optsBegin + optsAdd 'prio|tag|p|t' --mandatory + optsDone; eval "${optsCode}" + } + { + if [[ -n "$2" ]]; then + diff -U0 "$1" "$2" + else + cat $1 + fi + } | grep -v -e '^@@ ' -e '^--- ' -e '^+++ ' | while IFS= read line; do + Log "$line" "$prio" + done + LogMore__ -f "end" +}; #}}} + + +# LogRun ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# log info about execution to Debug level +LogRun() { + local pref='' + [[ "$1" =~ ^-f([0-9]*) ]] && { + shift + pref="-f$((${BASH_REMATCH[1]:-1}+1))" + } + LogMore + local dolog=$? + [[ $dolog -eq 0 ]] || { + local param params blacklist="[[:space:]]|>|<|\|" + [[ "${#@}" -eq 1 ]] && params="$1" || { + for param in "$@"; do + if [[ "$param" =~ $blacklist ]]; then + params="$params \"${param//\"/\\\"}\"" + else + params="$params $param" + fi + done + params="${params:1}" + } + LogDo $pref "executing >>>>> ${params} <<<<<" + } + eval "$@" + ret=$? + [[ $dolog -eq 0 ]] || LogMore $pref "execution >>>>> ${params} <<<<< returned '$ret'" + return $ret +}; # end of LogRun }}} + + +# LogDebugNext ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# log info about execution to Debug level +LogDebugNext() { + local pref='' + [[ "$1" =~ ^-f([0-9]*) ]] && { + shift + pref="-f$((${BASH_REMATCH[1]:-1}))" + } + LogDebug '' ${1:-$__INTERNAL_Log_level_DEBUG} || { + __INTERNAL_Log_DEBUGING=0 + trap " + __INTERNAL_Log_DEBUGING_res=\$? + let __INTERNAL_Log_DEBUGING++ + if [[ \$__INTERNAL_Log_DEBUGING -eq 1 ]]; then + __INTERNAL_Log_DEBUGING_cmd=\"\$BASH_COMMAND\" + LogDebug $pref \"executing >>>>> \$__INTERNAL_Log_DEBUGING_cmd <<<<<\" ${1:-$__INTERNAL_Log_level_DEBUG} + else + trap - DEBUG + LogDebug $pref \"execution >>>>> \$__INTERNAL_Log_DEBUGING_cmd <<<<< returned \$__INTERNAL_Log_DEBUGING_res\" ${1:-$__INTERNAL_Log_level_DEBUG} + fi" DEBUG + } +}; # end of LogDebugNext }}} + + +# LogMoreNext ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# log info about execution to Debug level +LogMoreNext() { + LogMore || { + local pref='' + [[ "$1" =~ ^-f([0-9]*) ]] && { + shift + pref="-f$((${BASH_REMATCH[1]:-1}))" + } + LogDebugNext $pref ${1:-$__INTERNAL_Log_level_MORE} + } +}; # end of LogMoreNext }}} +LogNext() { + LogMoreNext "$@" +} + + +# LogDebugOn ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# log info about execution to Debug level +LogDebugOn() { + local pref='' + [[ "$1" =~ ^-f([0-9]*) ]] && { + shift + pref="-f$((${BASH_REMATCH[1]:-1}))" + } + LogDebug '' ${1:-$__INTERNAL_Log_level_DEBUG} || { + trap " + __INTERNAL_Log_DEBUGING_res=\$? + let __INTERNAL_Log_DEBUGING++ + if [[ -z \"\$__INTERNAL_Log_DEBUGING_cmd\" ]]; then + __INTERNAL_Log_DEBUGING_cmd=\"\$BASH_COMMAND\" + LogDebug $pref \"executing >>>>> \$__INTERNAL_Log_DEBUGING_cmd <<<<<\" ${1:-$__INTERNAL_Log_level_DEBUG} + else + LogDebug $pref \"execution >>>>> \$__INTERNAL_Log_DEBUGING_cmd <<<<< returned \$__INTERNAL_Log_DEBUGING_res\" ${1:-$__INTERNAL_Log_level_DEBUG} + __INTERNAL_Log_DEBUGING_cmd=\"\$BASH_COMMAND\" + if [[ \"\$__INTERNAL_Log_DEBUGING_cmd\" =~ LogDebugOff ]]; then + trap - DEBUG + else + LogDebug $pref \"executing >>>>> \$__INTERNAL_Log_DEBUGING_cmd <<<<<\" ${1:-$__INTERNAL_Log_level_DEBUG} + fi + fi" DEBUG + } +}; # end of LogDebugOn }}} + + +# LogMoreOn ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# log info about execution to Debug level +LogMoreOn() { + LogMore || { + local pref='' + [[ "$1" =~ ^-f([0-9]*) ]] && { + shift + pref="-f$((${BASH_REMATCH[1]:-1}))" + } + LogDebugOn $pref ${1:-$__INTERNAL_Log_level_MORE} + } +}; # end of LogMoreOn }}} + + +# LogDebugOff ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# log info about execution to Debug level +LogDebugOff() { + __INTERNAL_Log_DEBUGING_cmd='' +}; # end of LogDebugOff }}} + + +# LogVar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +LogVar() { + [[ -n "$DEBUG" ]] && { + echo -n 'eval ' + while [[ -n "$1" ]]; do + echo -n "LogDebug -f \"\$(set | grep -P '^$1=')\";" + shift + done + } +}; # end of LogVar }}} + + +# __INTERNAL_LogRedirectToBeakerlib ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_LogRedirectToBeakerlib() { + echo -e "\nrunning inside the beakerlib - redirect own logging functions to beakerlib ones" + true; LogjAddMessage() { + LogMore___ -f "begin $*" + rljAddMessage "$2" "$1" + LogMore___ -f "end $*" + } + true; Log() { + LogMore___ -f "begin $*" + case ${2} in + INFO) + LogjAddMessage "INFO" "$1" + LogPrintMessage "$2" "${__INTERNAL_Log_prefix}${__INTERNAL_Log_prefix2}${1}${__INTERNAL_Log_postfix}" + ;; + BEGIN) + LogjAddMessage "INFO" "$*:" + LogPrintMessage "$2" "${__INTERNAL_Log_prefix}${__INTERNAL_Log_prefix2}${1}${__INTERNAL_Log_postfix}" + ;; + WARNING|WARN|ERROR|FATAL) + LogjAddMessage "WARNING" "$1" + LogPrintMessage "$2" "${__INTERNAL_Log_prefix}${__INTERNAL_Log_prefix2}${1}${__INTERNAL_Log_postfix}" + ;; + SKIP|SKIPPING) + LogjAddMessage "WARNING" "$*:" + LogPrintMessage "$2" "${__INTERNAL_Log_prefix}${__INTERNAL_Log_prefix2}${1}${__INTERNAL_Log_postfix}" + ;; + FAIL) + rlFail "$*" + return $? + ;; + PASS) + rlPass "$*" + return $? + ;; + *) + rlLog "$*" + ;; + esac + LogMore___ -f "end $*" + return 0; + } +} +# end of __INTERNAL_LogRedirectToBeakerlib }}} + + +# LogLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +LogLibraryLoaded() { + declare -F rlDie > /dev/null && __INTERNAL_LogRedirectToBeakerlib + return 0 +}; # end of LogLibraryLoaded }}} + + +echo "done." + +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Dalibor Pospisil + +=back + +=cut + diff --git a/tests/run-as/distribution/Library/opts/Makefile b/tests/run-as/distribution/Library/opts/Makefile new file mode 100644 index 0000000..389fe25 --- /dev/null +++ b/tests/run-as/distribution/Library/opts/Makefile @@ -0,0 +1,48 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /distribution/Library/opts +# Description: Block style coding with ability of skipping parts. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/distribution/Library/opts +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) lib.sh Makefile + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Provides simple way for defining script's or function's options including help" >> $(METADATA) + @echo "Type: Library" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RhtsRequires: library(distribution/Log)" >> $(METADATA) + @echo "Provides: library(distribution/opts)" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/run-as/distribution/Library/opts/lib.sh b/tests/run-as/distribution/Library/opts/lib.sh new file mode 100644 index 0000000..180f7ba --- /dev/null +++ b/tests/run-as/distribution/Library/opts/lib.sh @@ -0,0 +1,338 @@ +#!/bin/bash +# Authors: Dalibor Pospíšil +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2013 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# library-prefix = opts +# library-version = 4 +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +__INTERNAL_opts_LIB_VERSION=4 +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib library opts + +=head1 DESCRIPTION + +This library provides simple way for defining script's or function's option +agruments including help. + +=head1 USAGE + +To use this functionality you need to import library distribution/opts and add +following line to Makefile. + + @echo "RhtsRequires: library(distribution/opts)" >> $(METADATA) + +B + + testfunction() { + optsBegin -h "Usage: $0 [options] + + options: + " + optsAdd 'flag1' --flag + optsAdd 'optional1|o' --optional + optsAdd 'Optional2|O' "echo opt \$1" --optional --long --var-name opt + optsAdd 'mandatory1|m' "echo man \$1" --mandatory + optsDone; eval "${optsCode}" + echo "$optional1" + echo "$opt" + echo "$mandatory1" + } + +=head1 FUNCTIONS + +=cut + +echo -n "loading library opts v$__INTERNAL_opts_LIB_VERSION... " + +# optsAdd ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +optsAdd() { + LogMoreMed -f "begin '$*'" + local GETOPT=$(getopt -q -o fomv:d:lh:l -l flag,opt,optional,mandatory,varname:,default:,local,help:,long -- "$@") + eval set -- "$GETOPT" + local type='f' var_name var_name_set default help long + while [[ -n "$@" ]]; do + case $1 in + --) + shift; break + ;; + -h|--help) + shift + help="$1" + ;; + -l|--long) + long=1 + ;; + -d|--default) + shift + default="$1" + ;; + -v|--varname|--var-name) + shift + var_name="$1" + var_name_set=1 + ;; + -f|--flag) + type='f' + ;; + -o|--opt|--optional) + type='o' + ;; + -m|--mandatory) + type='m' + ;; + *) + echo "unknown option '$1'" + return 1 + ;; + esac + shift; + done + [ -z "$var_name" ] && { + var_name=$(echo -n "$1" | cut -d '|' -f 1 | sed -e 's/-//g;s/^[0-9]/_\0/') + LogMoreHigh -f "constructing variable name '$var_name'" + } + local opts='' opts_help='' optsi='' + for optsi in $(echo -n "$1" | tr '|' ' '); do + if [[ ${#optsi} -ge 2 || $long -eq 1 ]]; then + opts="$opts|--$optsi" + opts_help="$opts_help|--$optsi[=ARG]" + __INTERNAL_opts_long="${__INTERNAL_opts_long},${optsi}" + LogMoreHigh -f "adding long option '$optsi'" + case $type in + m) + __INTERNAL_opts_long="${__INTERNAL_opts_long}:" + ;; + o) + __INTERNAL_opts_long="${__INTERNAL_opts_long}::" + ;; + esac + else + opts="$opts|-$optsi" + opts_help="$opts_help|-${optsi}[ARG]" + __INTERNAL_opts_short="${__INTERNAL_opts_short}${optsi}" + LogMoreHigh -f "adding short option '$optsi'" + case $type in + m) + __INTERNAL_opts_short="${__INTERNAL_opts_short}:" + ;; + o) + __INTERNAL_opts_short="${__INTERNAL_opts_short}::" + ;; + esac + fi + done + optsCode="${optsCode} + ${opts:1}) + optsPresent=\"\${optsPresent}$var_name \"" + LogMoreHigh -f "adding code for processing option '${opts:1}'" + __INTERNAL_opts_init_var="$__INTERNAL_opts_init_var +${__INTERNAL_opts_local}$var_name=()" + __INTERNAL_opts_default="$__INTERNAL_opts_default +[[ \"\$optsPresent\" =~ \$(echo \"\<${var_name}\>\") ]] || ${__INTERNAL_opts_local}$var_name='$default'" + case $type in + f) + [[ -z "$2" || -n "$var_name_set" ]] && { + local val=1 + [[ -n "$default" ]] && val='' + optsCode="$optsCode + $var_name+=( '$val' )" + } + __INTERNAL_opts_help="${__INTERNAL_opts_help} + ${opts:1}" + ;; + o|m) + optsCode="$optsCode + shift" + [[ -z "$2" || -n "$var_name_set" ]] && optsCode="$optsCode + $var_name+=( \"\$1\" )" + if [[ "$type" == "o" ]]; then + __INTERNAL_opts_help="${__INTERNAL_opts_help} + ${opts_help:1}" + else + __INTERNAL_opts_help="${__INTERNAL_opts_help} + ${opts:1} ARG" + fi + ;; + esac + [[ -n "$2" ]] && { + optsCode="$optsCode + $2" + } + optsCode="$optsCode + ;;" + + __INTERNAL_opts_help="${__INTERNAL_opts_help}${help:+ + $help +}" + LogMoreMed -f "end" +}; # end of optsAdd }}} + + +# optsBegin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +optsBegin() { + LogMoreMed -f "begin '$*'" + optsCode='' + optsPresent=' ' + __INTERNAL_opts_short='.' + __INTERNAL_opts_long='help' + __INTERNAL_opts_help='' + __INTERNAL_opts_local='' + __INTERNAL_opts_default='' + __INTERNAL_opts_init_var='' + [[ "${FUNCNAME[1]}" != "main" ]] && __INTERNAL_opts_local='local ' + while [[ -n "$1" ]]; do + case $1 in + --) + shift; break + ;; + -h|--help) + shift + __INTERNAL_opts_help="$1" + ;; + *) + echo "unknown option '$1'" + return 1 + ;; + esac + shift; + done + LogMoreMed -f "end" +}; # end of optsBegin }}} + + +# optsDone ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +optsDone() { + LogMoreMed -f "begin '$*'" + optsCode="${__INTERNAL_opts_local}GETOPT=\$(getopt -o ${__INTERNAL_opts_short} -l ${__INTERNAL_opts_long} -- \"\$@\") +[[ \$? -ne 0 ]] && { + echo 'Exiting' + return 1 >& /dev/null + exit 1 +} +eval set -- \"\$GETOPT\" +${__INTERNAL_opts_init_var:1} +while [[ -n \"\$1\" ]]; do + case \$1 in + --) + shift; break + ;; +${optsCode} + + --help) + echo \"\$__INTERNAL_opts_help\" + return >& /dev/null + exit + ;; + *) + echo \"unknown option '\$1'\" + return 1 >& /dev/null + exit 1 + ;; + esac + shift +done +${__INTERNAL_opts_default:1} +unset optsCode __INTERNAL_opts_help __INTERNAL_opts_short __INTERNAL_opts_long __INTERNAL_opts_default __INTERNAL_opts_init_var __INTERNAL_opts_local +" + if ! echo "$optsCode" | grep -q -- '--help$'; then + __INTERNAL_opts_help="$__INTERNAL_opts_help + --help + Show this help." + fi + LogMoreHigh -f "optsCode:\n$optsCode" + LogMoreMed -f "end" +}; # end of optsDone }}} + + +# optsSelfCheck ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +optsSelfCheck() { + optsBegin -h "Usage: $0 [options] + + options: +" +# optsAdd 'help' -f 'echo help' + optsAdd 'flag' -f 'echo f' + optsAdd 'optional|o' -o "echo opt \$1" + optsAdd 'Optional|O' -o "echo opt \$1" --long + optsAdd 'mandatory|m' -m "echo man \$1" + optsDone + + echo "${optsCode}" + + echo ... + + eval "${optsCode}" + + echo ... + + fce() { + optsBegin -h "Usage: $0 [options] + + options: +" + # optsAdd 'help' -f 'echo help' + optsAdd 'flag' -f + optsAdd 'optional|o' -o "echo opt \$1" + optsAdd 'Optional|O' -o "echo opt \$1" --long + optsAdd 'mandatory|m' -m "echo man \$1" + optsDone + echo "${optsCode}" + + echo ... + + eval "${optsCode}" + + echo ... + } + + echo -e 'test for opts in function\n=========================' + fce --help +}; # end of optsSelfCheck }}} + + +# optsLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +optsLibraryLoaded() { + return 0 +}; # end of LogLibraryLoaded }}} + + +echo "done." + +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Dalibor Pospisil + +=back + +=cut + diff --git a/tests/run-as/distribution/Library/tcf/Makefile b/tests/run-as/distribution/Library/tcf/Makefile new file mode 100644 index 0000000..2566969 --- /dev/null +++ b/tests/run-as/distribution/Library/tcf/Makefile @@ -0,0 +1,60 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /distribution/Library/tcf +# Description: Block style coding with ability of skipping parts. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/distribution/Library/tcf +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) lib.sh Makefile + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Block style coding with ability of skipping parts." >> $(METADATA) + @echo "Type: Library" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RhtsRequires: library(distribution/Log)" >> $(METADATA) + @echo "Provides: library(distribution/tcf)" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/run-as/distribution/Library/tcf/lib.sh b/tests/run-as/distribution/Library/tcf/lib.sh new file mode 100644 index 0000000..561b0ff --- /dev/null +++ b/tests/run-as/distribution/Library/tcf/lib.sh @@ -0,0 +1,903 @@ +#!/bin/bash +# try-check-final.sh +# Authors: Dalibor Pospíšil +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# library-prefix = tcf +# library-version = 14 +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +__INTERNAL_tcf_LIB_VERSION=14 +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib library Try-Check-Final + +=head1 DESCRIPTION + +This file contains functions which gives user the ability to define blocks of +code where some of the blocks can be automatically skipped if some of preceeding +blocks failed. + +ATTENTION +This plugin modifies some beakerlib functions! If you suspect that it breakes +some functionality set the environment variable TCF_NOHACK to nonempty value. + +=head1 USAGE + +To use this functionality you need to import library distribution/tcf and add +following line to Makefile. + + @echo "RhtsRequires: library(distribution/tcf)" >> $(METADATA) + +=head1 FUNCTIONS + +=cut + +echo -n "loading library try-check-final v$__INTERNAL_tcf_LIB_VERSION... " + + +let __INTERNAL_tcf_DEBUG_LEVEL_LOW=3 +let __INTERNAL_tcf_DEBUG_LEVEL_MED=$__INTERNAL_tcf_DEBUG_LEVEL_LOW+1 +let __INTERNAL_tcf_DEBUG_LEVEL_HIGH=$__INTERNAL_tcf_DEBUG_LEVEL_LOW+2 + +# global variables {{{ +__INTERNAL_tcf_result=0 +__INTERNAL_tcf_result_file="${BEAKERLIB_DIR:-"/var/tmp"}/tcf.result" +echo -n "$__INTERNAL_tcf_result" > "$__INTERNAL_tcf_result_file" +__INTERNAL_tcf_current_level_data=() +__INTERNAL_tcf_current_level_val=0 +__INTERNAL_tcf_journal=() +#}}} + + +# __INTERNAL_tcf_colorize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_colorize() { + local a + case $1 in + PASS) + a="${__INTERNAL_tcf_color_green}${1}${__INTERNAL_tcf_color_reset}" + ;; + FAIL) + a="${__INTERNAL_tcf_color_red}${1}${__INTERNAL_tcf_color_reset}" + ;; + SKIPPING|WARNING) + a="${__INTERNAL_tcf_color_yellow}${1}${__INTERNAL_tcf_color_reset}" + ;; + BEGIN|INFO) + a="${__INTERNAL_tcf_color_blue}${1}${__INTERNAL_tcf_color_reset}" + ;; + *) + a=$1 + esac + echo -n "$a" +}; # end of __INTERNAL_tcf_colorize }}} + + +# __INTERNAL_tcf_colors_setup ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_colors_setup(){ + T="$TERM" + [[ -t 1 ]] || T="" + [[ -t 2 ]] || T="" + [[ "$1" == "--force" ]] && T="xterm" + case $T in + xterm|screen) + __INTERNAL_tcf_color_black="\e[0;30m" + __INTERNAL_tcf_color_dark_gray="\e[1;30m" + __INTERNAL_tcf_color_blue="\e[0;34m" + __INTERNAL_tcf_color_light_blue="\e[1;34m" + __INTERNAL_tcf_color_green="\e[0;32m" + __INTERNAL_tcf_color_light_green="\e[1;32m" + __INTERNAL_tcf_color_cyan="\e[0;36m" + __INTERNAL_tcf_color_light_cyan="\e[1;36m" + __INTERNAL_tcf_color_red="\e[0;31m" + __INTERNAL_tcf_color_light_red="\e[1;31m" + __INTERNAL_tcf_color_purple="\e[0;35m" + __INTERNAL_tcf_color_light_purple="\e[1;35m" + __INTERNAL_tcf_color_brown="\e[0;33m" + __INTERNAL_tcf_color_yellow="\e[1;33m" + __INTERNAL_tcf_color_light_gray="\e[0;37m" + __INTERNAL_tcf_color_white="\e[1;37m" + __INTERNAL_tcf_color_reset="\e[00m" + ;; + * ) + __INTERNAL_tcf_color_black="" + __INTERNAL_tcf_color_dark_gray="" + __INTERNAL_tcf_color_blue="" + __INTERNAL_tcf_color_light_blue="" + __INTERNAL_tcf_color_green="" + __INTERNAL_tcf_color_light_green="" + __INTERNAL_tcf_color_cyan="" + __INTERNAL_tcf_color_light_cyan="" + __INTERNAL_tcf_color_red="" + __INTERNAL_tcf_color_light_red="" + __INTERNAL_tcf_color_purple="" + __INTERNAL_tcf_color_light_purple="" + __INTERNAL_tcf_color_brown="" + __INTERNAL_tcf_color_yellow="" + __INTERNAL_tcf_color_light_gray="" + __INTERNAL_tcf_color_white="" + __INTERNAL_tcf_color_reset="" + ;; + esac +}; # end of __INTERNAL_tcf_colors_setup +__INTERNAL_tcf_colors_setup; # }}} + + +# __INTERNAL_tcf_copy_function ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_copy_function() { + declare -F $1 > /dev/null || return 1 + eval "$(echo -n "${2}() "; declare -f ${1} | tail -n +2)" +}; # end of __INTERNAL_tcf_copy_function }}} + + +# __INTERNAL_tcf_addE2R ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_addE2R() { + __INTERNAL_tcf_copy_function $1 TCF_orig_$1 + eval "${1}() { TCF_orig_${1} \"\$@\"; tcfE2R; }" +}; # end of __INTERNAL_tcf_addE2R }}} + + +# __INTERNAL_tcf_insertE2R ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_insertE2R() { + __INTERNAL_tcf_copy_function $1 TCF_orig_$1 + eval "$(echo -n "${1}() "; declare -f ${1} | tail -n +2 | sed -e 's/\(.*__INTERNAL_ConditionalAssert.*\)/\1\ntcfE2R;/')" +}; # end of __INTERNAL_tcf_insertE2R }}} + + +# __INTERNAL_tcf_get_current_level ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_get_current_level() { + local l=$__INTERNAL_tcf_current_level_val + if [[ $1 ]]; then + l=$(($l+$1)) + fi + local i + for i in $(seq 1 $(($l*2)) ); do echo -n " "; done + return $l +}; # end of __INTERNAL_tcf_get_current_level }}} + + +# __INTERNAL_tcf_incr_current_level ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_incr_current_level() { + let __INTERNAL_tcf_current_level_val++ + __INTERNAL_Log_prefix=$(__INTERNAL_tcf_get_current_level) +}; # end of __INTERNAL_tcf_incr_current_level }}} + + +# __INTERNAL_tcf_decr_current_level ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_decr_current_level() { + let __INTERNAL_tcf_current_level_val-- + __INTERNAL_Log_prefix=$(__INTERNAL_tcf_get_current_level) +}; # end of __INTERNAL_tcf_decr_current_level }}} + + +# __INTERNAL_tcf_do_hack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_do_hack() { + LogDebug "TCF_NOHACK='$TCF_NOHACK'" + if [[ -z "$TCF_NOHACK" ]]; then + tcfChk "Apply TCF beakerlib hacks" && { + rlLog " injecting tcf hacks into the beakerlib functions" + echo -n "patching rlLog" + local rlL=$(declare -f rlLog | sed -e 's|\] ::|\0${__INTERNAL_Log_prefix}|;s|$3 $1"|${3:+"$3 "}$1"|') + eval "$rlL" + + echo -n ", rljAddTest" + __INTERNAL_tcf_copy_function rljAddTest __INTERNAL_tcf_orig_rljAddTest + true; rljAddTest() { + local a="${__INTERNAL_Log_prefix}$1"; shift + [[ "$1" != "FAIL" ]]; tcfE2R + __INTERNAL_tcf_journal=("${__INTERNAL_tcf_journal[@]}" "$1" "$a") + __INTERNAL_tcf_orig_rljAddTest "$a" "$@" + } + echo -n ", rljAddMessage" + __INTERNAL_tcf_copy_function rljAddMessage __INTERNAL_tcf_orig_rljAddMessage + true; rljAddMessage() { + local a="${__INTERNAL_Log_prefix}$1"; shift + __INTERNAL_tcf_journal=("${__INTERNAL_tcf_journal[@]}" "$1" "$a") + __INTERNAL_tcf_orig_rljAddMessage "$a" "$@" + } + echo -n ", __INTERNAL_LogAndJournalFail" + __INTERNAL_tcf_copy_function __INTERNAL_LogAndJournalFail __INTERNAL_tcf_orig___INTERNAL_LogAndJournalFail + true; __INTERNAL_LogAndJournalFail() { + tcfNOK + __INTERNAL_tcf_orig___INTERNAL_LogAndJournalFail "$@" + } + echo "." + tcfFin --no-assert --ignore; } + else + Log "skip hacking beakerlib functions" + fi +}; # end of __INTERNAL_tcf_do_hack }}} + + +# __INTERNAL_tcf_kill_old_plugin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_kill_old_plugin() { + tcfChk "Get rid of the old TCF implementation. removing" && { + local comma='' i + for i in Try Chk Fin E2R RES OK NOK NEG TCFcheckFinal TCFreport; do + echo -n "${comma}rl$i" + unset -f rl$i + comma=', ' + done + echo '.' + tcfFin --no-assert; } +}; # end of __INTERNAL_tcf_kill_old_plugin }}} + + +: <<'=cut' +=pod + +=head2 Block functions + +=cut + +# __INTERNAL_tcf_parse_params ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_parse_params() { + local GETOPT=$(getopt -q -o if: -l ignore,no-assert,fail-tag: -- "$@") + eval set -- "$GETOPT" + echo "local ignore noass title fail_tag" + echo "[ -z \"\$ignore\" ] && ignore=0" + echo "[ -z \"\$noass\" ] && noass=0" + echo "[ -z \"\$fail_tag\" ] && fail_tag='FAIL'" + while [[ -n "$@" ]]; do + case $1 in + --) + shift; break + ;; + --ignore|-i) + echo "ignore=1" + echo "noass=1" + ;; + --no-assert|-n) + echo "noass=1" + ;; + --fail-tag|-f) + shift + echo "fail_tag='$1'" + ;; + *) + echo "unknown option $1" + return 1 + ;; + esac + shift; + done + [[ -n "$1" ]] && echo "title=\"${1}\"" + echo "eval set -- \"$(echo "$GETOPT" | sed -e 's/.*-- //')\"" +}; # end of __INTERNAL_tcf_parse_params }}} + + +# tcfTry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfTry + +Starting function of block which will be skipped if an error has been detected +by tcfFin function occurent before. + + tcfTry ["title"] [-i|--ignore] [--no-assert] [--fail-tag TAG] && { + + tcfFin; } + +If title is omitted than noting is printed out so no error will be reported (no +Assert is executed) thus at least the very top level tcfTry should have title. + +tcfTry and tcfChk blocks are stackable so you can organize them into a hierarchy +structure. + +Note that tcfFin has to be used otherwise the overall result will not be +accurate. + +=over + +=item title + +Text which will be displayed and logged at the beginning and the end (in tcfFin +function) of the block. + +=item -i, --ignore + +Do not propagate the actual result to the higher level result. + +=item -n, --no-assert + +Do not log error into the journal. + +=item -f, --fail-tag TAG + +If the result of the block is FAIL, use TAG instead ie. INFO or WARNING. + +=back + +Returns 1 if and error occured before, otherwise returns 0. + +=cut + +tcfTry() { + LogMoreLow -f "begin '$*'" + local vars=$(__INTERNAL_tcf_parse_params "$@") || { Log "$vars" FAIL; return 1; } + LogMoreMed -f "vars:\n$vars" + LogMoreLow -f "evaluating options start" + eval "$vars" + LogMoreLow -f "evaluating options end" + local incr= + local pp="SKIPPING" + tcfRES; # to set __INTERNAL_tcf_result + LogMoreLow -f "result was $__INTERNAL_tcf_result" + if [[ $__INTERNAL_tcf_result -eq 0 ]]; then + __INTERNAL_tcf_current_level_data=("$__INTERNAL_tcf_result" "$vars" "${__INTERNAL_tcf_current_level_data[@]}") + pp="BEGIN" + incr=1 + fi + if [[ -n "$title" ]]; then + Log "$title" "$pp" + [[ -n "$incr" ]] && { + LogMoreLow -f "increment indentation level" + __INTERNAL_tcf_incr_current_level + } + fi + LogMoreLow -f "end" + return $__INTERNAL_tcf_result +}; # end of tcfTry }}} + + +# tcfChk ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfChk + +Starting function of block which will be always executed. + + tcfChk ["title"] [-i|--ignore] [--no-assert] [--fail-tag TAG] && { + + tcfFin; } + +If title is omitted than noting is printed out so no error will be reported (no +Assert is executed) thus at least the very top level tcfChk should have title. + +tcfTry and tcfChk blocks are stackable so you can organize them into a hierarchy +structure. + +Note that tcfFin has to be used otherwise the overall result will not be +accurate. + +For details about arguments see tcfTry. + +Returns 0. + +=cut + +tcfChk() { + LogMoreLow -f "begin '$*'" + tcfRES; # to set __INTERNAL_tcf_result + local res=$__INTERNAL_tcf_result + tcfRES 0 + tcfTry "$@" + __INTERNAL_tcf_current_level_data[0]=$res + LogMoreLow -f "end" + return $__INTERNAL_tcf_result +}; # end of tcfChk }}} + + +# tcfFin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfFin + +Ending function of block. It does some evaluation of previous local and global +results and puts it into the global result. + + tcfTry ["title"] && { + + tcfFin [-i|--ignore] [--no-assert] [--fail-tag TAG]; } + +Local result is actualy exit code of the last command int the body. + +Global result is an internal varibale hodning previous local results. +Respectively last error or 0. + +For details about arguments see tcfTry. + +Returns local result of the preceeding block. + +=cut + +tcfFin() { + local RES=$? + LogMoreLow -f "begin '$*'" + LogMoreMed -f "previous exit code was '$RES'" + local vars=$(__INTERNAL_tcf_parse_params "$@") || { Log "$vars" FAIL; return 1; } + LogMoreMed -f "vars:\n$vars" + LogMoreLow -f "evaluating options start" + eval "$vars" + LogMoreLow -f "evaluating options end" + tcfRES; # to set __INTERNAL_tcf_result + [[ $RES -ne 0 ]] && tcfRES $RES + RES=$__INTERNAL_tcf_result + LogMoreMed -f "overall result is '$RES'" + LogMoreMed -f "data:\n${__INTERNAL_tcf_current_level_data[1]}" + LogMoreLow -f "evaluating data start" + eval "${__INTERNAL_tcf_current_level_data[1]}" + LogMoreLow -f "evaluating data end" + if [[ -n "$title" ]]; then + __INTERNAL_tcf_decr_current_level + if [[ $ignore -eq 1 ]]; then + RES=0 + [[ $__INTERNAL_tcf_result -ne 0 ]] && title="$title - ignored" + fi + if [[ $noass -eq 0 ]]; then + tcfAssert0 "$title" $__INTERNAL_tcf_result "$fail_tag" + else + if [[ $__INTERNAL_tcf_result -eq 0 ]]; then + local pp="PASS" + LogInfo "$title - $pp" + else + local pp="${fail_tag:-FAIL}" + LogWarn "$title - $pp" + fi + fi + fi + if [[ $__INTERNAL_tcf_result -eq 0 || $ignore -eq 1 ]]; then + tcfRES ${__INTERNAL_tcf_current_level_data[0]} + fi + local i + for i in 0 1; do unset __INTERNAL_tcf_current_level_data[$i]; done + __INTERNAL_tcf_current_level_data=("${__INTERNAL_tcf_current_level_data[@]}") + LogMoreLow -f "end" + return $RES +}; # end of tcfFin }}} + +: <<'=cut' +=pod + +=head2 Functions for manipulation with the results + +=cut + + +# tcfRES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfRES + +Sets and return the global result. + + tcfRES [-p|--print] [number] + +=over + +=item -p --print + +Also print the result value. + +=item number + +If present the global result is set to this value. + +=back + +Returns global result. + +=cut + +tcfRES() { + local p=0 + while [[ -n "$1" ]]; do + case $1 in + --print|-p) + p=1 + ;; + *) + break + ;; + esac + shift + done + if [[ -n "$1" ]]; then + __INTERNAL_tcf_result=$1 + echo -n "$__INTERNAL_tcf_result" > "$__INTERNAL_tcf_result_file" + else + __INTERNAL_tcf_result="$(cat "$__INTERNAL_tcf_result_file")" + fi + [[ $p -eq 1 ]] && echo $__INTERNAL_tcf_result + return $__INTERNAL_tcf_result +}; # end of tcfRES }}} + + +# tcfOK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfOK + +Sets the global result to 0. + + tcfOK + +Returns global result. + +=cut + +tcfOK() { + tcfRES 0 +}; # end of tcfOK }}} + + +# tcfNOK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfNOK + +Sets the global result to 1 or given number. + + tcfNOK [number] + +=over + +=item number + +If present the global result is set to this value. + +=back + +Returns global result. + +=cut + +tcfNOK() { + if [[ -n "$1" ]]; then + [[ $1 -eq 0 ]] && echo "You have requested result '0'. You should use tcfOK instead." + tcfRES $1 + else + tcfRES 1 + fi +}; # end of tcfNOK }}} + + +# tcfE2R ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfE2R + +Converts exit code of previous command to local result if the exit code is not 0 +(zero). + + + tcfE2R [number] + +=over + +=item number + +If present use it instead of exit code. + +=back + +Returns original exit code or given number. + +=cut + +tcfE2R() { + local res=$? + [[ -n "$1" ]] && res=$1 + [[ $res -ne 0 ]] && tcfRES $res + return $res +}; # end of tcfE2R }}} + + +: <<'=cut' +=pod + +=head2 Functions for manipulation with the exit codes + +=cut + + +# tcfNEG ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfNEG + +Negates exit code of previous command. + + + tcfNEG + +Returns 1 if original exit code was 0, otherwise returns 0. + +=cut + +tcfNEG() { + [[ $? -eq 0 ]] && return 1 || return 0 +}; # end of tcfNEG }}} + + +# tcfRun ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfRun + +Simmilar to rlRun but it also annouces the beginnign of the command. + + tcfRun [--fail-tag|-f TAG] command [exp_result [title]] + +Moreover if 'command not found' appears on STDERR it should produce WARNING. + +=over + +=item command + +Command to execute. + +=item exp_result + +Specification of expect resutl. + +It can be a list of values or intervals or * for any result. Also negation (!) can be used. + + Example: + + <=2,7,10-12,>252,!254 means following values 0,1,2,7,10,11,12,253,255 + +=item title + +Text which will be displayed and logged at the beginning and the end of command execution. + +=item --fail-tag | -f + +If the command fails use TAG instead of FAIL. + +=back + +Returns exit code of the executed command. + +=cut + +tcfRun() { + LogMore_ -f "begin $*" + optsBegin + optsAdd 'fail-tag|f' --mandatory + optsAdd 'timeout' --optional 'timeout="${1:-10}"' + optsAdd 'kill-timeout|kt' --mandatory --default 5 + optsAdd 'signal' --mandatory --default TERM + optsAdd 'check-code' --mandatory --default 'kill -0 $cmdpid >&/dev/null' + optsAdd 'kill-code' --mandatory --default '/bin/kill -$signal -- $cmdpid' + optsAdd 'allow-skip|as' --flag + optsAdd 'no-assert|n' --flag + optsDone; eval "${optsCode}" + LogMore_ -f "after opts $*" + [[ -z "$allowskip" ]] && tcfChk + local orig_expecode="${2:-0}" + local expecode="$orig_expecode" + [[ "$expecode" == "*" ]] && expecode="0-255" + local command="$1" + local comment="Running command '$command'" + [[ -n "$3" ]] && comment="$3" + [[ -n "$expecode" ]] && { + expecode=$(echo "$expecode" | tr ',-' '\n ' | sed -e 's/^!=/!/;s/^=//;s/^<=\(.\+\)$/0 \1/;s/^>=\(.\+\)$/\1 255/;s/^<\(.\+\)$/0 \$(( \1 - 1 ))/;s/^>\(.\+\)$/\$(( \1 + 1 )) 255/' | while read line; do [[ "$line" =~ ^[^\ ]+$ ]] && echo "$line" || eval seq $line; done; ) + tcfE2R + LogMoreLow -f "orig_expecode='$orig_expecode'" + LogMoreLow -f "expecode='$expecode'" + } + tcfTry ${noassert:+--no-assert} "$comment" && { + local errout=$(mktemp) + LogMoreLow -f "executing '$command'" + if [[ "$optsPresent" =~ $(echo "\") ]]; then + LogDebug -f "using watchdog feature" + local ec="$(mktemp)" + eval "$command; echo $? > $ec 2> >(tee $errout)" & + local cmdpid=$! + local time_start=$(date +%s) + local timeout_t=$(( $time_start + $timeout )) + while true; do + if ! eval "$checkcode"; then + Log "command finished in $(($(date +%s) - $time_start )) seconds" + local res="$(cat $ec)" + break + elif [[ $(date +%s) -ge $timeout_t ]]; then + echo + Log "command is still running, sending $signal signal" + eval "$killcode" + tcfNOK 255 + echo 255 > $ec + let timeout_t+=killtimeout + signal=KILL + fi + sleep 0.1 + done + rm -f $ec + else + eval "$command" 2> >(tee $errout) + local res=$? + fi + LogMoreLow -f "got '$res'" + local resmatch=$(echo "$expecode" | grep "^\!\?${res}$") + LogMoreLow -f "resmatch='$resmatch'" + [[ -n "$resmatch" && ! "$resmatch" =~ '!' ]] + if tcfE2R; then + ! grep -iq "command not found" $errout || { failtag='WARNING'; tcfNOK; } + else + Log "Expected result was '$orig_expecode', got '$res'!" + fi + tcfFin ${failtag:+--fail-tag "$failtag"}; } + rm -f $errout + [[ -z "$allowskip" ]] && tcfFin + LogMore_ -f "end $*" + return $res +}; # end of tcfRun }}} + + +: <<'=cut' +=pod + +=head2 Functions for logging + +=cut + + +# tcfAssert0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +tcfAssert0() { + LogMoreLow -f "begin '$*'" + local RES="${3:-FAIL}" + [[ $2 -eq 0 ]] && RES='PASS' + Log "$1" $RES + LogMoreLow -f "end" +}; # end of tcfAssert0 }}} + + +# tcfCheckFinal ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfCheckFinal + +Check that all tcfTry / tcfChk functions have been close by tcfFin. + + tcfCheckFinal + +=cut + +tcfCheckFinal() { + tcfAssert0 "Check that TCF block cache is empty" ${#__INTERNAL_tcf_current_level_data[@]} + tcfAssert0 "Check that TCF current level is 0" $__INTERNAL_tcf_current_level_val +}; # end of tcfCheckFinal }}} + + +echo "done." + +: <<'=cut' +=pod + +=head2 Self check functions + +=cut + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# tcfSelfCheck {{{ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +: <<'=cut' +=pod + +=head3 tcfSelfCheck + +Does some basic functionality tests. + + tcfSelfCheck + +The function is called also by the following command: + + ./lib.sh selfcheck + +=cut + + +tcfSelfCheck() { + tcfChk "check 1" &&{ + tcfTry "try 1.1 - true" &&{ + true + tcfFin;} + tcfTry "try 1.2 - false" &&{ + false + tcfFin;} + tcfTry "try 1.3 - true" &&{ + true + tcfFin;} + tcfFin;} + tcfChk "check 2" &&{ + tcfTry "try 2.1 - true" &&{ + true + tcfFin;} + tcfTry "try 2.2 - true - ignore" &&{ + true + tcfFin -i;} + tcfTry "try 2.3 - true" &&{ + true + tcfFin;} + tcfFin;} + tcfChk "check 3" &&{ + tcfTry "try 3.1 - true" &&{ + true + tcfFin;} + tcfTry "try 3.2 - false - ignore" &&{ + false + tcfFin -i;} + tcfTry "try 3.3 - true" &&{ + true + tcfFin;} + tcfFin;} + tcfCheckFinal + tcfAssert0 "Overall result" $(tcfRES -p) + LogReport +} +if [[ "$1" == "selfcheck" ]]; then + tcfSelfCheck +fi; # end of tcfSelfCheck }}} + + +# tcfLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +tcfLibraryLoaded() { + rlImport distribution/Log + declare -F rlDie > /dev/null && { + #rlJournalStart + #rlPhaseStartSetup "TCF" + echo -e "\nrunning inside the beakerlib - using rlAssert0" + true; tcfAssert0() { + local text="$1" + [[ "$3" != "FAIL" && "$3" != "PASS" ]] && text="$text - $3" + __INTERNAL_ConditionalAssert "$text" "$2" + } + __INTERNAL_tcf_do_hack + #rlPhaseEnd + #rlJournalEnd + }; + if declare -F rlE2R >& /dev/null; then + __INTERNAL_tcf_kill_old_plugin + fi + true +}; # end of tcfLibraryLoaded }}} + + +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Dalibor Pospisil + +=back + +=cut + + diff --git a/tests/run-as/distribution/Library/testUser/Makefile b/tests/run-as/distribution/Library/testUser/Makefile new file mode 100644 index 0000000..037162e --- /dev/null +++ b/tests/run-as/distribution/Library/testUser/Makefile @@ -0,0 +1,60 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /distribution/Library/testUser +# Description: Block style coding with ability of skipping parts. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/distribution/Library/testUser +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) lib.sh Makefile + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Setup/cleanup standard testing user." >> $(METADATA) + @echo "Type: Library" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RhtsRequires: library(distribution/Log)" >> $(METADATA) + @echo "Provides: library(distribution/testUser)" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/run-as/distribution/Library/testUser/lib.sh b/tests/run-as/distribution/Library/testUser/lib.sh new file mode 100644 index 0000000..24da7a6 --- /dev/null +++ b/tests/run-as/distribution/Library/testUser/lib.sh @@ -0,0 +1,234 @@ +#!/bin/bash +# try-check-final.sh +# Authors: Dalibor Pospíšil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# library-prefix = testUser +# library-version = 7 +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib library testUser + +=head1 DESCRIPTION + +This library provide s function for maintaining testing users. + +=head1 USAGE + +To use this functionality you need to import library distribution/testUser and add +following line to Makefile. + + @echo "RhtsRequires: library(distribution/testUser)" >> $(METADATA) + +=head1 VARIABLES + +=over + +=item testUser + +Array of testing user login names. + +=item testUserPasswd + +Array of testing users passwords. + +=item testUserUID + +Array of testing users UIDs. + +=item testUserGID + +Array of testing users primary GIDs. + +=item testUserGroup + +Array of testing users primary group names. + +=item testUserGIDs + +Array of space separated testing users all GIDs. + +=item testUserGroups + +Array of space separated testing users all group names. + +=item testUserGecos + +Array of testing users gecos fields. + +=item testUserHomeDir + +Array of testing users home directories. + +=item testUserShell + +Array of testing users default shells. + +=back + +=head1 FUNCTIONS + +=cut + +echo -n "loading library testUser... " + +: <<'=cut' +=pod + +=head3 testUserSetup, testUserCleanup + +Creates/removes testing user(s). + + rlPhaseStartSetup + testUserSetup [NUM] + rlPhaseEnd + + rlPhaseStartCleanup + testUserCleanup + rlPhaseEnd + +=over + +=item NUM + +Optional number of user to be created. If not specified one user is created. + +=back + +Returns 0 if success. + +=cut + + +testUserSetup() { + # parameter dictates how many users should be created, defaults to 1 + local res=0 + local count_created=0 + local count_wanted=${1:-"1"} + local index=0 + (( $count_wanted < 1 )) && return 1 + + while (( $count_created != $count_wanted ));do + let index++ + local newUser="testuser${index}" + local newUserPasswd="redhat" + id "$newUser" &> /dev/null && continue # if user with the name exists, try again + + # create + useradd -m $newUser >&2 || ((res++)) + echo "$newUserPasswd" | passwd --stdin $newUser || ((res++)) + + # save the users array + testUser+=($newUser) + testUserPasswd+=($newUserPasswd) + set | grep "^testUser=" > $__INTERNAL_testUser_users_file + set | grep "^testUserPasswd=" >> $__INTERNAL_testUser_users_file + ((count_created++)) + done + __INTERNAL_testUserRefillInfo || ((res++)) + + echo ${res} + [[ $res -eq 0 ]] +} + + +__INTERNAL_testUserRefillInfo() { + local res=0 + local user + testUserUID=() + testUserGID=() + testUserGroup=() + testUserGIDs=() + testUserGroups=() + testUserGecos=() + testUserHomeDir=() + testUserShell=() + + for user in ${testUser[@]}; do + local ent_passwd=$(getent passwd ${user}) || ((res++)) + local users_id="$(id ${user})" || ((res++)) + # testUser is filled during user creation - already present + # testUserPasswd is saved same way as testUser - already present + testUserUID+=("$(echo "$ent_passwd" | cut -d ':' -f 3)") + testUserGID+=("$(echo "$ent_passwd" | cut -d ':' -f 4)") + testUserGroup+=("$(echo "$users_id" | sed -r 's/.*gid=(\S+).*/\1/;s/[[:digit:]]+\(//g;s/\)//g;s/,/ /g')") + testUserGIDs+=("$(echo "$users_id" | sed -r 's/.*groups=(\S+).*/\1/;s/\([^\)]+\)//g;s/\)//g;s/,/ /g')") + testUserGroups+=("$(echo "$users_id" | sed -r 's/.*groups=(\S+).*/\1/;s/[[:digit:]]+\(//g;s/\)//g;s/,/ /g')") + testUserGecos+=("$(echo "$ent_passwd" | cut -d ':' -f 5)") + testUserHomeDir+=("$(echo "$ent_passwd" | cut -d ':' -f 6)") + testUserShell+=("$(echo "$ent_passwd" | cut -d ':' -f 7)") + done + + echo ${res} + [[ $res -eq 0 ]] +} + + +testUserCleanup() { + local res=0 + for user in ${testUser[@]}; do + userdel -rf "$user" >&2 || ((res++)) + done + unset testUser + __INTERNAL_testUserRefillInfo + rm -f $__INTERNAL_testUser_users_file >&2 || ((res++)) + + echo ${res} + [[ $res -eq 0 ]] +} + + + +# testUserLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +testUserLibraryLoaded() { + local res=0 + # necessary init steps + __INTERNAL_testUser_users_file="$BEAKERLIB_DIR/users" + + # try to fill in users array with previous data + [[ -f ${__INTERNAL_testUser_users_file} ]] && . ${__INTERNAL_testUser_users_file} >&2 + __INTERNAL_testUserRefillInfo >&2 || ((res++)) + + [[ $res -eq 0 ]] +}; # end of testUserLibraryLoaded }}} + + +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Dalibor Pospisil + +=back + +=cut + +echo "done." + diff --git a/tests/run-as/runtest.sh b/tests/run-as/runtest.sh new file mode 100755 index 0000000..13fcd5b --- /dev/null +++ b/tests/run-as/runtest.sh @@ -0,0 +1,163 @@ +#!/bin/bash +# vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# runtest.sh of /CoreOS/sudo/Sanity/run-as +# Description: Test feature 'run as'. This means -u, -g options. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2017 Red Hat, Inc. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1151, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include Beaker environment +. /usr/bin/rhts-environment.sh || exit 1 +. /usr/share/beakerlib/beakerlib.sh || exit 1 + +PACKAGE="sudo" + +rlJournalStart && { + rlPhaseStartSetup && { + [[ -z "$BEAKERLIB_LIBRARY_PATH" ]] && BEAKERLIB_LIBRARY_PATH="`dirname "$(readlink -f "$0")"`" + rlRun "rlImport --all" 0 "Import libraries" || rlDie "cannot continue" + tcfRun "rlCheckMakefileRequires" + rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory" + CleanupRegister "rlRun 'rm -r $TmpDir' 0 'Removing tmp directory'" + CleanupRegister 'rlRun "popd"' + rlRun "pushd $TmpDir" + CleanupRegister 'tcfRun "testUserCleanup"' + tcfRun "testUserSetup 5" + CleanupRegister 'rlRun "rlFileRestore"' + rlRun "rlFileBackup --clean /etc/sudoers.d" + cat > /etc/sudoers.d/testing << EOF + Defaults !requiretty + $testUser ALL = (ALL:ALL) NOPASSWD: ALL + ${testUser[1]} ALL = ( ${testUser[0]} ) NOPASSWD: ALL + ${testUser[2]} ALL = ( ${testUser[0]}, ${testUser[1]} ) NOPASSWD: ALL + ${testUser[3]} ALL = ( : ${testUserGroup[1]}, ${testUser[0]} ) NOPASSWD: ALL + ${testUser[4]} ALL = ( ${testUser[0]} : ${testUserGroup[2]} ) NOPASSWD: ALL +EOF + rlRun "cat /etc/sudoers.d/testing" + rlPhaseEnd; } + + CMD='bash -c "ps -o user:15,group:15,ruser:15,rgroup:15,args --ppid $$"' + + tcfTry "Tests" --no-assert && { + test() { + local who="$1" as="$2" as_grp="$3" exp_res="$4" + if [[ -z "$exp_res" || "$exp_res" == "0" ]]; then + rlRun -s "su -l $who -c 'sudo ${as:+-u $as} ${as_grp:+-g $as_grp} $CMD'" + [[ -n "$as_grp" && -z "$as" ]] && as="$who" + as="${as:-root}" + as_grp="${as_grp:-$as}" + rlAssertGrep "$as\s+$as_grp\s+$as\s+$as_grp\s+" $rlRun_LOG -Eq + rm -f $rlRun_LOG + else + rlRun -s "su -l $who -c 'sudo ${as:+-u $as} ${as_grp:+-g $as_grp} $CMD'" 1 + [[ -n "$as_grp" && -z "$as" ]] && as="$who" + as="${as:-root}" + as_grp="${as_grp:-$as}" + rlAssertNotGrep "$as\s+$as_grp\s+$as\s+$as_grp\s+" $rlRun_LOG -Eq + rm -f $rlRun_LOG + fi + } + rlPhaseStartTest "run as a default user" && { + tcfChk "Test phase" && { + tcfChk "$testUser can run as all" && { + test $testUser "" "" "" 0 + tcfFin; } + tcfChk "${testUser[1]} cannot run as anyone" && { + test ${testUser[1]} "" "" 1 + tcfFin; } + tcfChk "${testUser[2]} cannot run as anyone" && { + test ${testUser[2]} "" "" 1 + tcfFin; } + tcfFin; } + rlPhaseEnd; } + + rlPhaseStartTest "run as a user (-u)" && { + tcfChk "Test phase" && { + tcfChk "$testUser can run as all" && { + test $testUser "root" "" 0 + test $testUser "${testUser[1]}" "" 0 + test $testUser "${testUser[2]}" "" 0 + tcfFin; } + tcfChk "${testUser[1]} can run as $testUser" && { + test ${testUser[1]} "root" "" 1 + test ${testUser[1]} "${testUser[0]}" "" 0 + test ${testUser[1]} "${testUser[2]}" "" 1 + tcfFin; } + tcfChk "${testUser[2]} can run as $testUser and ${testUser[1]}" && { + test ${testUser[2]} "root" "" 1 + test ${testUser[2]} "${testUser[0]}" "" 0 + test ${testUser[2]} "${testUser[1]}" "" 0 + tcfFin; } + tcfFin; } + rlPhaseEnd; } + + rlPhaseStartTest "run as a group (-g)" && { + tcfChk "Test phase" && { + tcfChk "$testUser can run as all" && { + test $testUser "" "root" 0 + test $testUser "" "${testUserGroup[1]}" 0 + test $testUser "" "${testUserGroup[2]}" 0 + tcfFin; } + tcfChk "${testUser[4]} can run as ${testUserGroup[2]}" && { + test ${testUser[4]} "" "root" 1 + test ${testUser[4]} "" "${testUserGroup[0]}" 1 + test ${testUser[4]} "" "${testUserGroup[2]}" 0 + tcfFin; } + #tcfChk "${testUser[2]} can run as ${testUserGroup[1]}" && { + # test ${testUser[2]} "" "root" 1 + # test ${testUser[2]} "" "${testUserGroup[1]}" 1 + # test ${testUser[2]} "" "${testUserGroup[2]}" 1 + #tcfFin; } + #tcfChk "${testUser[3]}" && { + # test ${testUser[2]} "" "root" 1 + # test ${testUser[2]} "" "${testUserGroup[1]}" 0 + # test ${testUser[2]} "" "${testUserGroup[2]}" 0 + #tcfFin; } + tcfFin; } + rlPhaseEnd; } + + rlPhaseStartTest "run as both user (-u) and group (-g)" && { + tcfChk "Test phase" && { + tcfChk "$testUser can run as all" && { + test $testUser "${testUser[1]}" "root" 0 + test $testUser "${testUser[2]}" "${testUserGroup[1]}" 0 + test $testUser "${testUser[1]}" "${testUserGroup[2]}" 0 + tcfFin; } + tcfChk "${testUser[4]} can run as ${testUser[0]} ${testUserGroup[2]}" && { + test ${testUser[4]} "${testUser[0]}" "root" 1 + test ${testUser[4]} "${testUser[0]}" "${testUserGroup[0]}" 0 + #test ${testUser[4]} "${testUser[0]}" "${testUserGroup[4]}" 0 + test ${testUser[4]} "${testUser[4]}" "${testUserGroup[4]}" 0 + test ${testUser[4]} "${testUser[0]}" "${testUserGroup[3]}" 1 + test ${testUser[4]} "${testUser[0]}" "${testUserGroup[2]}" 0 + tcfFin; } + tcfFin; } + rlPhaseEnd; } + tcfFin; } + + rlPhaseStartCleanup && { + CleanupDo + tcfCheckFinal + rlPhaseEnd; } + rlJournalPrintText +rlJournalEnd; } diff --git a/tests/sudoers-options-sanity-test/Makefile b/tests/sudoers-options-sanity-test/Makefile new file mode 100644 index 0000000..cc8a3bd --- /dev/null +++ b/tests/sudoers-options-sanity-test/Makefile @@ -0,0 +1,67 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /CoreOS/sudo/Sanity/sudoers-options-sanity-test +# Description: This sanity test checks pre-defined (some are commented) options (examples) in sudoers file. +# Author: Ales Marecek +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2013 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/CoreOS/sudo/Sanity/sudoers-options-sanity-test +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) runtest.sh Makefile PURPOSE + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Ales Marecek " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "RhtsRequires: library(distribution/tcf)" >> $(METADATA) + @echo "RhtsRequires: library(distribution/Cleanup)" >> $(METADATA) + @echo "RhtsRequires: library(distribution/ConditionalPhases)" >> $(METADATA) + @echo "RhtsRequires: library(distribution/testUser)" >> $(METADATA) + @echo "Description: This sanity test checks pre-defined (some are commented) options (examples) in sudoers file." >> $(METADATA) + @echo "Type: Sanity" >> $(METADATA) + @echo "TestTime: 30m" >> $(METADATA) + @echo "RunFor: sudo" >> $(METADATA) + @echo "Requires: sudo grep coreutils" >> $(METADATA) + @echo "Priority: Normal" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + @echo "Confidential: no" >> $(METADATA) + @echo "Destructive: no" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/sudoers-options-sanity-test/PURPOSE b/tests/sudoers-options-sanity-test/PURPOSE new file mode 100644 index 0000000..3bff2f9 --- /dev/null +++ b/tests/sudoers-options-sanity-test/PURPOSE @@ -0,0 +1,3 @@ +PURPOSE of /CoreOS/sudo/Sanity/sudoers-options-sanity-test +Description: This sanity test checks pre-defined (some are commented) options (examples) in sudoers file. +Author: Ales Marecek diff --git a/tests/sudoers-options-sanity-test/distribution/Library/Cleanup/Makefile b/tests/sudoers-options-sanity-test/distribution/Library/Cleanup/Makefile new file mode 100644 index 0000000..3e5a8e1 --- /dev/null +++ b/tests/sudoers-options-sanity-test/distribution/Library/Cleanup/Makefile @@ -0,0 +1,59 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /distribution/Library/Cleanup +# Description: Block style coding with ability of skipping parts. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/distribution/Library/Cleanup +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) lib.sh Makefile + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Provides function to define cleanup stack which can do its work at any time of the test run." >> $(METADATA) + @echo "Type: Library" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "Provides: library(distribution/Cleanup)" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/sudoers-options-sanity-test/distribution/Library/Cleanup/lib.sh b/tests/sudoers-options-sanity-test/distribution/Library/Cleanup/lib.sh new file mode 100644 index 0000000..c66d21c --- /dev/null +++ b/tests/sudoers-options-sanity-test/distribution/Library/Cleanup/lib.sh @@ -0,0 +1,314 @@ +#!/bin/bash +# Authors: Dalibor Pospíšil +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# library-prefix = Cleanup +# library-version = 9 +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +__INTERNAL_Cleanup_LIB_VERSION=9 +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib library Cleanup + +=head1 DESCRIPTION + +This file contains functions which provides cleanup stack functionality. + +=head1 USAGE + +To use this functionality you need to import library distribution/Cleanup and add +following line to Makefile. + + @echo "RhtsRequires: library(distribution/Cleanup)" >> $(METADATA) + +B + + rlJournalStart + rlPhaseStartSetup + rlImport 'distribution/Cleanup' + tmp=$(mktemp) + CleanupRegister " + rlLog 'Removing data' + rlRun \"rm -f ${tmp}\" + " + rlLog 'Creating some data' + rlRun "echo 'asdfalkjh' > $tmp" + + CleanupRegister " + rlLog 'just something to demonstrate unregistering' + " + ID1=$CleanupRegisterID + CleanupUnregister $ID1 + + CleanupRegister " + rlLog 'just something to demonstrate partial cleanup' + " + ID2=$CleanupRegisterID + CleanupRegister "rlLog 'cleanup some more things'" + # cleanup everything upto ID2 + CleanupDo $ID2 + + CleanupRegister --mark " + rlLog 'yet another something to demonstrate partial cleanup using internal ID saving' + " + CleanupRegister "rlLog 'cleanup some more things'" + # cleanup everything upto last mark + CleanupDo --mark + rlPhaseEnd + + rlPhaseStartCleanup + CleanupDo + rlPhaseEnd + + rlJournalPrintText + rlJournalEnd + +=head1 FUNCTIONS + +=cut + +echo -n "loading library Cleanup v$__INTERNAL_Cleanup_LIB_VERSION... " + +__INTERNAL_Cleanup_stack_file="$BEAKERLIB_DIR/Cleanup_stack" +touch "$__INTERNAL_Cleanup_stack_file" +chmod ug+rw "$__INTERNAL_Cleanup_stack_file" + +# CleanupRegister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# CleanupRegister [--mark] CLEANUP_CODE +# --mark - also mark this position +CleanupRegister() { + local mark=0 + [[ "$1" == "--mark" ]] && { + mark=1 + shift + } + if ! CleanupGetStack; then + rlLogError "cannot continue, could not get cleanup stack" + return 1 + fi + CleanupRegisterID="${RANDOM}$(date +"%s%N")" + echo -n "Registering cleanup ID=$CleanupRegisterID" >&2 + if [[ $mark -eq 1 ]]; then + __INTERNAL_CleanupMark=( "$CleanupRegisterID" "${__INTERNAL_CleanupMark[@]}" ) + echo -n " with mark" >&2 + fi + echo " '$1'" >&2 + rlLogDebug "prepending '$1'" + local ID_tag="# ID='$CleanupRegisterID'" + __INTERNAL_Cleanup_stack="$ID_tag +$1 +$ID_tag +$__INTERNAL_Cleanup_stack" + if ! CleanupSetStack "$__INTERNAL_Cleanup_stack"; then + rlLogError "an error occured while registering the cleanup '$1'" + return 1 + fi + return 0 +}; # end of CleanupRegister }}} + + +# __INTERNAL_Cleanup_get_stack_part ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# 1: ID +# -ID - everything upto the ID +# 2: '' - return ID only +# 'rest' - return exact oposit +__INTERNAL_Cleanup_get_stack_part() { + rlLogDebug "__INTERNAL_Cleanup_get_stack_part(): $* begin" + local ID="$1" + local n='1 0 1' + local stack='' + [[ "${ID:0:1}" == "-" ]] && { + ID="${ID:1}" + n='0 0 1' + } + [[ "$2" == "rest" ]] && { + n="$(echo "${n//0/2}")" + n="$(echo "${n//1/0}")" + n="$(echo "${n//2/1}")" + } + n=($n) + [[ -n "$DEBUG" ]] && rlLogDebug "$(set | grep ^n=)" + local ID_tag="# ID='$ID'" + while IFS= read -r line; do + + [[ "$line" == "$ID_tag" ]] && { + n=( "${n[@]:1}" ) + continue + } + if [[ $n -eq 0 ]]; then + stack="$stack +$line" + fi + done < <(echo "$__INTERNAL_Cleanup_stack") + rlLogDebug "__INTERNAL_Cleanup_get_stack_part(): cleanup stack part is '${stack:1}'" + echo "${stack:1}" + rlLogDebug "__INTERNAL_Cleanup_get_stack_part(): $* end" +}; # end of __INTERNAL_Cleanup_get_stack_part }}} + +# CleanupUnregister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +CleanupUnregister() { + local ID="$1" + rlLog "Unregistering cleanup ID='$ID'" + if ! CleanupGetStack; then + rlLogError "cannot continue, could not get cleanup stack" + return 1 + fi + rlLogDebug "removing ID='$ID'" + if ! CleanupSetStack "$(__INTERNAL_Cleanup_get_stack_part "$ID" 'rest')"; then + rlLogError "an error occured while registering the cleanup '$1'" + return 1 + fi + return 0 +}; # end of CleanupUnregister }}} + + +# CleanupMark ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_CleanupMark=() +CleanupMark() { + echo -n "Setting cleanup mark" >&2 + CleanupRegister --mark '' 2>/dev/null + local res=$? + echo " ID='$CleanupRegisterID'" >&2 + return $res +}; # end of CleanupMark }}} + + +# CleanupDo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# 1: '' - cleanup all +# ID - cleanup ID only +# -ID - cleanup all upto ID, including +# mark - cleanup all unto last mark, including +CleanupDo() { + local ID="$1" + if ! CleanupGetStack; then + rlLogError "cannot continue, could not get cleanup stack" + return 1 + fi + local res tmp newstack='' + tmp="$(mktemp)" + if [[ "$ID" == "mark" || "$ID" == "--mark" ]]; then + echo "execute cleanup upto mark='$__INTERNAL_CleanupMark'" >&2 + __INTERNAL_Cleanup_get_stack_part "-$__INTERNAL_CleanupMark" | grep -v "^# ID='" > "$tmp" + newstack="$(__INTERNAL_Cleanup_get_stack_part "-$__INTERNAL_CleanupMark" 'rest')" + __INTERNAL_CleanupMark=("${__INTERNAL_CleanupMark[@]:1}") + elif [[ -n "$ID" ]]; then + echo "execute cleanup for ID='$ID'" >&2 + __INTERNAL_Cleanup_get_stack_part "$ID" | grep -v "^# ID='" > "$tmp" + newstack="$(__INTERNAL_Cleanup_get_stack_part "$ID" 'rest')" + else + CleanupTrapUnhook + trap "echo 'temporarily blocking ctrl+c until cleanup is done' >&2" SIGINT + cat "$__INTERNAL_Cleanup_stack_file" | grep -v "^# ID='" > "$tmp" + echo "execute whole cleanup stack" >&2 + fi + . "$tmp" + res=$? + [[ $res -ne 0 ]] && { + echo "cleanup code:" >&2 + cat -n "$tmp" >&2 + } + rm -f "$tmp" + echo "cleanup execution done" >&2 + if [[ -z "$ID" ]]; then + trap - SIGINT + fi + if ! CleanupSetStack "$newstack"; then + rlLogError "an error occured while cleaning the stack" + return 1 + fi + return $res +}; # end of CleanupDo }}} + + +# CleanupGetStack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +CleanupGetStack() { + rlLogDebug "getting cleanup stack" + if [[ -r "$__INTERNAL_Cleanup_stack_file" ]]; then + if __INTERNAL_Cleanup_stack="$(cat "$__INTERNAL_Cleanup_stack_file")"; then + rlLogDebug "cleanup stack is '$__INTERNAL_Cleanup_stack'" + return 0 + fi + fi + rlLogError "could not load cleanup stack" + return 1 +}; # end of CleanupGetStack }}} + + +# CleanupSetStack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +CleanupSetStack() { + rlLogDebug "setting cleanup stack to '$1'" + __INTERNAL_Cleanup_stack="$1" + if echo "$__INTERNAL_Cleanup_stack" > "$__INTERNAL_Cleanup_stack_file"; then + rlLogDebug "cleanup stack is now '$__INTERNAL_Cleanup_stack'" + return 0 + fi + rlLogError "could not set cleanup stack" + return 1 +}; # end of CleanupSetStack }}} + + +__INTERNAL_Cleanup_signals='' +__INTERNAL_Cleanup_trap_code='rlJournalStart; rlPhaseStartCleanup; CleanupDo; rlPhaseEnd; rlJournalPrintText; rlJournalEnd; exit' +# CleanupTrapHook ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +CleanupTrapHook() { + rlLog "register cleanup trap" + __INTERNAL_Cleanup_signals="${1:-"SIGHUP SIGINT SIGTERM EXIT"}" + eval "trap \"${__INTERNAL_Cleanup_trap_code}\" $__INTERNAL_Cleanup_signals" +}; # end of CleanupTrapHook }}} + + +# CleanupTrapUnhook ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +CleanupTrapUnhook() { + if [[ -n "$__INTERNAL_Cleanup_signals" ]]; then + rlLog "unregister cleanup trap" + eval trap - $__INTERNAL_Cleanup_signals + __INTERNAL_Cleanup_signals='' + fi +}; # end of CleanupTrapUnhook }}} + + +# CleanupLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +CleanupLibraryLoaded() { + CleanupTrapHook +}; # end of CleanupLibraryLoaded }}} + + +echo "done." + +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Dalibor Pospisil + +=back + +=cut + diff --git a/tests/sudoers-options-sanity-test/distribution/Library/ConditionalPhases/Makefile b/tests/sudoers-options-sanity-test/distribution/Library/ConditionalPhases/Makefile new file mode 100644 index 0000000..f017bcb --- /dev/null +++ b/tests/sudoers-options-sanity-test/distribution/Library/ConditionalPhases/Makefile @@ -0,0 +1,59 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /distribution/Library/ConditionalPhases +# Description: Implements conditional phases. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/distribution/Library/ConditionalPhases +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) lib.sh Makefile + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Implements conditional phases." >> $(METADATA) + @echo "Type: Library" >> $(METADATA) + @echo "Provides: library(distribution/ConditionalPhases)" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/sudoers-options-sanity-test/distribution/Library/ConditionalPhases/lib.sh b/tests/sudoers-options-sanity-test/distribution/Library/ConditionalPhases/lib.sh new file mode 100644 index 0000000..39024d1 --- /dev/null +++ b/tests/sudoers-options-sanity-test/distribution/Library/ConditionalPhases/lib.sh @@ -0,0 +1,166 @@ +#!/bin/bash +# Authors: Dalibor Pospíšil +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# library-prefix = ConditionalPhases +# library-version = 2 +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +__INTERNAL_ConditionalPhases_LIB_VERSION=2 +__INTERNAL_ConditionalPhases_LIB_NAME='distribution/ConditionalPhases' +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib library distribution/condpahses + +=head1 DESCRIPTION + +Implements conditional phases to eficiently select test phases to be execute +using white and black lists. + +To use this functionality you need to import library +distribution/ConditionalPhases and add following line to Makefile. + + @echo "RhtsRequires: library(distribution/ConditionalPhases)" >> $(METADATA) + +=head1 USAGE + +=head2 Conditional phases + +Each test phase can be conditionally skipped based on a bash regular expression +given in CONDITIONAL_PHASES_BL and/or CONDITIONAL_PHASES_WL variables. + +=over + +=item CONDITIONAL_PHASES_BL + +It is a black list. If match phase name the respective phase should be skipped. + +=item CONDITIONAL_PHASES_WL + +It is a white list. If does B match phase name the respective phase should +be skipped excluding phases contatning 'setup' or 'cleanup' in its name. Names +'setup' and 'cleanup' are matched case insenitively. + +=back + +Actual skipping has to be done in the test case itself by using return code of +functions I, I, I, and +I. + +Example: + + rlPhaseStartTest "phase name" && { + ... + rlPhaseEnd; } + +Evaluation of the phase relevancy works as follows: + 1. If CONDITIONAL_PHASES_BL is non-empty and matches phase name => return 2. + 2. If phase name contains word 'setup' or 'cleanup' or CONDITIONAL_PHASES_WL + is empty => return 0. + 3. If CONDITIONAL_PHASES_WL is non-empty and matches phase name => return 0 + otherwise return 1. + +Normaly Setup and Cleanup phases are not skipped unless hey are B +black-listed. + +To make the test work properly with conditional phases it is necessary to +surround phase code with curly brackets and make it conditionally executed +based on rlPhaseStart* function's exit code the same way as it is demostrated in +the example above. To make the process easy you can use following command: + + sed 's/rlPhaseStart[^{]*$/& \&\& {/;s/rlPhaseEnd[^}]*$/&; }/' + +This code can be embedded in Makefile by modifying build target to following +form: + + build: $(BUILT_FILES) + grep -Eq 'rlPhase(Start[^{]*|End[^}]*)$' runtest.sh && sed -i 's/rlPhaseStart[^{]*$/& \&\& {/;s/rlPhaseEnd[^}]*$/&; }/' testrun.sh + test -x runtest.sh || chmod a+x runtest.sh + + +=cut +#' +echo -n "loading library $__INTERNAL_ConditionalPhases_LIB_NAME v$__INTERNAL_ConditionalPhases_LIB_VERSION... " + + +# ConditionalPhasesLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +ConditionalPhasesLibraryLoaded() { + if [[ -n "$CONDITIONAL_PHASES_BL" || -n "$CONDITIONAL_PHASES_WL" ]]; then + __INTERNAL_ConditionalPhases_eval() { + # check phases black-list + [[ -n "$CONDITIONAL_PHASES_BL" && "$1" =~ $CONDITIONAL_PHASES_BL ]] && { + rlLogWarning "phase '$1' should be skipped as it is defined in \$CONDITIONAL_PHASES_BL='$CONDITIONAL_PHASES_BL'" + return 2 + } + # always execute Setup, Cleanup and if no PHASES (white-list) specified + [[ "$1" =~ $(echo "\<[Ss][Ee][Tt][Uu][Pp]\>") || "$1" =~ $(echo "\<[Cc][Ll][Ee][Aa][Nn][Uu][Pp]\>") ]] && { + rlLogInfo "phase '$1' will be executed as 'setup' and 'cleanup' phases are allowed by default, these can be black-listed" + return 0 + } + [[ -z "$CONDITIONAL_PHASES_WL" ]] && { + rlLogInfo "phase '$1' will be executed as there is no rule for it" + return 0 + } + [[ "$1" =~ $CONDITIONAL_PHASES_WL ]] && { + rlLogInfo "phase '$1' will be executed as it is defined in \$CONDITIONAL_PHASES_WL='$CONDITIONAL_PHASES_WL'" + return 0 + } || { + rlLogWarning "phase '$1' should be skipped as it is not defined in \$CONDITIONAL_PHASES_WL='$CONDITIONAL_PHASES_WL'" + return 1 + } + } + + rlLogInfo "replacing rlPhaseStart by modified function with conditional phases implemented" + :; rlPhaseStart() { + if [ "x$1" = "xFAIL" -o "x$1" = "xWARN" ] ; then + __INTERNAL_ConditionalPhases_eval "$2" && \ + rljAddPhase "$1" "$2" + return $? + else + rlLogError "rlPhaseStart: Unknown phase type: $1" + return 1 + fi + } + else + rlLogInfo "Neither CONDITIONAL_PHASES_WL nor CONDITIONAL_PHASES_BL is defined, not applying modifications" + fi +}; # end of ConditionalPhasesLibraryLoaded }}} + + +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Dalibor Pospisil + +=back + +=cut + +echo 'done.' diff --git a/tests/sudoers-options-sanity-test/distribution/Library/Log/Makefile b/tests/sudoers-options-sanity-test/distribution/Library/Log/Makefile new file mode 100644 index 0000000..3cf0e65 --- /dev/null +++ b/tests/sudoers-options-sanity-test/distribution/Library/Log/Makefile @@ -0,0 +1,48 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /distribution/Library/Log +# Description: Block style coding with ability of skipping parts. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/distribution/Library/Log +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) lib.sh Makefile + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Provides yet another logging facility that does not rely on beakerlib while it can integrate with it." >> $(METADATA) + @echo "Type: Library" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RhtsRequires: library(distribution/opts)" >> $(METADATA) + @echo "Provides: library(distribution/Log)" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/sudoers-options-sanity-test/distribution/Library/Log/lib.sh b/tests/sudoers-options-sanity-test/distribution/Library/Log/lib.sh new file mode 100644 index 0000000..ac1db3d --- /dev/null +++ b/tests/sudoers-options-sanity-test/distribution/Library/Log/lib.sh @@ -0,0 +1,637 @@ +#!/bin/bash +# Authors: Dalibor Pospíšil +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2013 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# library-prefix = Log +# library-version = 11 +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +__INTERNAL_Log_LIB_VERSION=11 +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib library Log + +=head1 DESCRIPTION + +This library provide logging capability which does not rely on beakerlib so it +can be used standalone. + +If it is used within beakerlib it automatically bypass all messages to the +beakerlib. + +Also this library provide journaling feature so the summary can be printed out +at the end. + +=head1 USAGE + +To use this functionality you need to import library distribution/Log and add +following line to Makefile. + + @echo "RhtsRequires: library(distribution/Log)" >> $(METADATA) + +=head1 FUNCTIONS + +=cut + +echo -n "loading library Log v$__INTERNAL_Log_LIB_VERSION... " + + +__INTERNAL_Log_prefix='' +__INTERNAL_Log_prefix2='' +__INTERNAL_Log_postfix='' +__INTERNAL_Log_default_level=3 +__INTERNAL_Log_level=$__INTERNAL_Log_default_level +LogSetDebugLevel() { + if [[ -n "$1" ]]; then + if [[ "$1" =~ ^[0-9]+$ ]]; then + let __INTERNAL_Log_level=$__INTERNAL_Log_default_level+$1; + else + __INTERNAL_Log_level=255 + fi + else + __INTERNAL_Log_level=$__INTERNAL_Log_default_level + fi +} +LogSetDebugLevel "$DEBUG" +let __INTERNAL_Log_level_LOG=0 +let __INTERNAL_Log_level_FATAL=0 +let __INTERNAL_Log_level_ERROR=1 +let __INTERNAL_Log_level_WARNING=2 +let __INTERNAL_Log_level_INFO=3 +let __INTERNAL_Log_level_DEBUG=4 +let __INTERNAL_Log_level_MORE=5 +let __INTERNAL_Log_level_MORE_=$__INTERNAL_Log_level_MORE+1 +let __INTERNAL_Log_level_MORE__=$__INTERNAL_Log_level_MORE_+1 +let __INTERNAL_Log_level_MORE___=$__INTERNAL_Log_level_MORE__+1 + +# Log ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +Log() { + LogMore___ -f "begin '$*'" + local pri=$2 message="${__INTERNAL_Log_prefix}${__INTERNAL_Log_prefix2}${1}${__INTERNAL_Log_postfix}" + if [[ -n "$pri" ]]; then + LogPrintMessage "$pri" "$message" + LogjAddMessage "$pri" "$message" + else + LogPrintMessage "$(date +%H:%M:%S)" "$message" + LogjAddMessage "INFO" "$message" + fi + LogMore___ -f "end" + return 0 +}; # end of Log }}} + + +__INTERNAL_Log_condition() { + cat <&2 + return 0 +}; # end of LogPrintMessage }}} + + +# LogReport ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 LogReport + +Prints final report similar to breakerlib's rlJournalPrintText. This is useful +mainly if you use TCF without beakerlib. + + LogReport + +=cut +#' + +LogReport() { + echo -e "\n ====== Summary report begin ======" + local a p l i + for i in $(seq 0 2 $((${#__INTERNAL_Log_journal[@]}-1)) ); do + LogPrintMessage "${__INTERNAL_Log_journal[$i]}" "${__INTERNAL_Log_journal[$((++i))]}" + done + echo " ======= Summary report end =======" + __INTERNAL_Log_journal=() +}; # end of LogReport }}} + + +# LogFile ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +LogFile() { + LogMore__ -f "begin '$*'" + local prio='' + [[ $# -ge 3 ]] && { + optsBegin + optsAdd 'prio|tag|p|t' --mandatory + optsDone; eval "${optsCode}" + } + cat $1 | while IFS= read line; do + Log "$line" "${prio:-$2}" + done + LogMore__ -f "end" +}; #}}} + + +# LogText ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +LogText() { + LogMore__ -f "begin '$*'" + local prio='' + [[ $# -ge 3 ]] && { + optsBegin + optsAdd 'prio|tag|p|t' --mandatory + optsDone; eval "${optsCode}" + } + { + if [[ "$1" == "-" ]]; then + cat - + else + echo "$1" + fi + } | while IFS= read line; do + Log "$line" "${prio:-$2}" + done + LogMore__ -f "end" +}; #}}} + + +# LogStrippedDiff ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +LogStrippedDiff() { + LogMore__ -f "begin '$*'" + local prio='' + [[ $# -ge 3 ]] && { + optsBegin + optsAdd 'prio|tag|p|t' --mandatory + optsDone; eval "${optsCode}" + } + { + if [[ -n "$2" ]]; then + diff -U0 "$1" "$2" + else + cat $1 + fi + } | grep -v -e '^@@ ' -e '^--- ' -e '^+++ ' | while IFS= read line; do + Log "$line" "$prio" + done + LogMore__ -f "end" +}; #}}} + + +# LogRun ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# log info about execution to Debug level +LogRun() { + local pref='' + [[ "$1" =~ ^-f([0-9]*) ]] && { + shift + pref="-f$((${BASH_REMATCH[1]:-1}+1))" + } + LogMore + local dolog=$? + [[ $dolog -eq 0 ]] || { + local param params blacklist="[[:space:]]|>|<|\|" + [[ "${#@}" -eq 1 ]] && params="$1" || { + for param in "$@"; do + if [[ "$param" =~ $blacklist ]]; then + params="$params \"${param//\"/\\\"}\"" + else + params="$params $param" + fi + done + params="${params:1}" + } + LogDo $pref "executing >>>>> ${params} <<<<<" + } + eval "$@" + ret=$? + [[ $dolog -eq 0 ]] || LogMore $pref "execution >>>>> ${params} <<<<< returned '$ret'" + return $ret +}; # end of LogRun }}} + + +# LogDebugNext ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# log info about execution to Debug level +LogDebugNext() { + local pref='' + [[ "$1" =~ ^-f([0-9]*) ]] && { + shift + pref="-f$((${BASH_REMATCH[1]:-1}))" + } + LogDebug '' ${1:-$__INTERNAL_Log_level_DEBUG} || { + __INTERNAL_Log_DEBUGING=0 + trap " + __INTERNAL_Log_DEBUGING_res=\$? + let __INTERNAL_Log_DEBUGING++ + if [[ \$__INTERNAL_Log_DEBUGING -eq 1 ]]; then + __INTERNAL_Log_DEBUGING_cmd=\"\$BASH_COMMAND\" + LogDebug $pref \"executing >>>>> \$__INTERNAL_Log_DEBUGING_cmd <<<<<\" ${1:-$__INTERNAL_Log_level_DEBUG} + else + trap - DEBUG + LogDebug $pref \"execution >>>>> \$__INTERNAL_Log_DEBUGING_cmd <<<<< returned \$__INTERNAL_Log_DEBUGING_res\" ${1:-$__INTERNAL_Log_level_DEBUG} + fi" DEBUG + } +}; # end of LogDebugNext }}} + + +# LogMoreNext ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# log info about execution to Debug level +LogMoreNext() { + LogMore || { + local pref='' + [[ "$1" =~ ^-f([0-9]*) ]] && { + shift + pref="-f$((${BASH_REMATCH[1]:-1}))" + } + LogDebugNext $pref ${1:-$__INTERNAL_Log_level_MORE} + } +}; # end of LogMoreNext }}} +LogNext() { + LogMoreNext "$@" +} + + +# LogDebugOn ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# log info about execution to Debug level +LogDebugOn() { + local pref='' + [[ "$1" =~ ^-f([0-9]*) ]] && { + shift + pref="-f$((${BASH_REMATCH[1]:-1}))" + } + LogDebug '' ${1:-$__INTERNAL_Log_level_DEBUG} || { + trap " + __INTERNAL_Log_DEBUGING_res=\$? + let __INTERNAL_Log_DEBUGING++ + if [[ -z \"\$__INTERNAL_Log_DEBUGING_cmd\" ]]; then + __INTERNAL_Log_DEBUGING_cmd=\"\$BASH_COMMAND\" + LogDebug $pref \"executing >>>>> \$__INTERNAL_Log_DEBUGING_cmd <<<<<\" ${1:-$__INTERNAL_Log_level_DEBUG} + else + LogDebug $pref \"execution >>>>> \$__INTERNAL_Log_DEBUGING_cmd <<<<< returned \$__INTERNAL_Log_DEBUGING_res\" ${1:-$__INTERNAL_Log_level_DEBUG} + __INTERNAL_Log_DEBUGING_cmd=\"\$BASH_COMMAND\" + if [[ \"\$__INTERNAL_Log_DEBUGING_cmd\" =~ LogDebugOff ]]; then + trap - DEBUG + else + LogDebug $pref \"executing >>>>> \$__INTERNAL_Log_DEBUGING_cmd <<<<<\" ${1:-$__INTERNAL_Log_level_DEBUG} + fi + fi" DEBUG + } +}; # end of LogDebugOn }}} + + +# LogMoreOn ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# log info about execution to Debug level +LogMoreOn() { + LogMore || { + local pref='' + [[ "$1" =~ ^-f([0-9]*) ]] && { + shift + pref="-f$((${BASH_REMATCH[1]:-1}))" + } + LogDebugOn $pref ${1:-$__INTERNAL_Log_level_MORE} + } +}; # end of LogMoreOn }}} + + +# LogDebugOff ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +# log info about execution to Debug level +LogDebugOff() { + __INTERNAL_Log_DEBUGING_cmd='' +}; # end of LogDebugOff }}} + + +# LogVar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +LogVar() { + [[ -n "$DEBUG" ]] && { + echo -n 'eval ' + while [[ -n "$1" ]]; do + echo -n "LogDebug -f \"\$(set | grep -P '^$1=')\";" + shift + done + } +}; # end of LogVar }}} + + +# __INTERNAL_LogRedirectToBeakerlib ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_LogRedirectToBeakerlib() { + echo -e "\nrunning inside the beakerlib - redirect own logging functions to beakerlib ones" + true; LogjAddMessage() { + LogMore___ -f "begin $*" + rljAddMessage "$2" "$1" + LogMore___ -f "end $*" + } + true; Log() { + LogMore___ -f "begin $*" + case ${2} in + INFO) + LogjAddMessage "INFO" "$1" + LogPrintMessage "$2" "${__INTERNAL_Log_prefix}${__INTERNAL_Log_prefix2}${1}${__INTERNAL_Log_postfix}" + ;; + BEGIN) + LogjAddMessage "INFO" "$*:" + LogPrintMessage "$2" "${__INTERNAL_Log_prefix}${__INTERNAL_Log_prefix2}${1}${__INTERNAL_Log_postfix}" + ;; + WARNING|WARN|ERROR|FATAL) + LogjAddMessage "WARNING" "$1" + LogPrintMessage "$2" "${__INTERNAL_Log_prefix}${__INTERNAL_Log_prefix2}${1}${__INTERNAL_Log_postfix}" + ;; + SKIP|SKIPPING) + LogjAddMessage "WARNING" "$*:" + LogPrintMessage "$2" "${__INTERNAL_Log_prefix}${__INTERNAL_Log_prefix2}${1}${__INTERNAL_Log_postfix}" + ;; + FAIL) + rlFail "$*" + return $? + ;; + PASS) + rlPass "$*" + return $? + ;; + *) + rlLog "$*" + ;; + esac + LogMore___ -f "end $*" + return 0; + } +} +# end of __INTERNAL_LogRedirectToBeakerlib }}} + + +# LogLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +LogLibraryLoaded() { + declare -F rlDie > /dev/null && __INTERNAL_LogRedirectToBeakerlib + return 0 +}; # end of LogLibraryLoaded }}} + + +echo "done." + +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Dalibor Pospisil + +=back + +=cut + diff --git a/tests/sudoers-options-sanity-test/distribution/Library/opts/Makefile b/tests/sudoers-options-sanity-test/distribution/Library/opts/Makefile new file mode 100644 index 0000000..389fe25 --- /dev/null +++ b/tests/sudoers-options-sanity-test/distribution/Library/opts/Makefile @@ -0,0 +1,48 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /distribution/Library/opts +# Description: Block style coding with ability of skipping parts. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/distribution/Library/opts +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) lib.sh Makefile + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Provides simple way for defining script's or function's options including help" >> $(METADATA) + @echo "Type: Library" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RhtsRequires: library(distribution/Log)" >> $(METADATA) + @echo "Provides: library(distribution/opts)" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/sudoers-options-sanity-test/distribution/Library/opts/lib.sh b/tests/sudoers-options-sanity-test/distribution/Library/opts/lib.sh new file mode 100644 index 0000000..180f7ba --- /dev/null +++ b/tests/sudoers-options-sanity-test/distribution/Library/opts/lib.sh @@ -0,0 +1,338 @@ +#!/bin/bash +# Authors: Dalibor Pospíšil +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2013 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# library-prefix = opts +# library-version = 4 +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +__INTERNAL_opts_LIB_VERSION=4 +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib library opts + +=head1 DESCRIPTION + +This library provides simple way for defining script's or function's option +agruments including help. + +=head1 USAGE + +To use this functionality you need to import library distribution/opts and add +following line to Makefile. + + @echo "RhtsRequires: library(distribution/opts)" >> $(METADATA) + +B + + testfunction() { + optsBegin -h "Usage: $0 [options] + + options: + " + optsAdd 'flag1' --flag + optsAdd 'optional1|o' --optional + optsAdd 'Optional2|O' "echo opt \$1" --optional --long --var-name opt + optsAdd 'mandatory1|m' "echo man \$1" --mandatory + optsDone; eval "${optsCode}" + echo "$optional1" + echo "$opt" + echo "$mandatory1" + } + +=head1 FUNCTIONS + +=cut + +echo -n "loading library opts v$__INTERNAL_opts_LIB_VERSION... " + +# optsAdd ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +optsAdd() { + LogMoreMed -f "begin '$*'" + local GETOPT=$(getopt -q -o fomv:d:lh:l -l flag,opt,optional,mandatory,varname:,default:,local,help:,long -- "$@") + eval set -- "$GETOPT" + local type='f' var_name var_name_set default help long + while [[ -n "$@" ]]; do + case $1 in + --) + shift; break + ;; + -h|--help) + shift + help="$1" + ;; + -l|--long) + long=1 + ;; + -d|--default) + shift + default="$1" + ;; + -v|--varname|--var-name) + shift + var_name="$1" + var_name_set=1 + ;; + -f|--flag) + type='f' + ;; + -o|--opt|--optional) + type='o' + ;; + -m|--mandatory) + type='m' + ;; + *) + echo "unknown option '$1'" + return 1 + ;; + esac + shift; + done + [ -z "$var_name" ] && { + var_name=$(echo -n "$1" | cut -d '|' -f 1 | sed -e 's/-//g;s/^[0-9]/_\0/') + LogMoreHigh -f "constructing variable name '$var_name'" + } + local opts='' opts_help='' optsi='' + for optsi in $(echo -n "$1" | tr '|' ' '); do + if [[ ${#optsi} -ge 2 || $long -eq 1 ]]; then + opts="$opts|--$optsi" + opts_help="$opts_help|--$optsi[=ARG]" + __INTERNAL_opts_long="${__INTERNAL_opts_long},${optsi}" + LogMoreHigh -f "adding long option '$optsi'" + case $type in + m) + __INTERNAL_opts_long="${__INTERNAL_opts_long}:" + ;; + o) + __INTERNAL_opts_long="${__INTERNAL_opts_long}::" + ;; + esac + else + opts="$opts|-$optsi" + opts_help="$opts_help|-${optsi}[ARG]" + __INTERNAL_opts_short="${__INTERNAL_opts_short}${optsi}" + LogMoreHigh -f "adding short option '$optsi'" + case $type in + m) + __INTERNAL_opts_short="${__INTERNAL_opts_short}:" + ;; + o) + __INTERNAL_opts_short="${__INTERNAL_opts_short}::" + ;; + esac + fi + done + optsCode="${optsCode} + ${opts:1}) + optsPresent=\"\${optsPresent}$var_name \"" + LogMoreHigh -f "adding code for processing option '${opts:1}'" + __INTERNAL_opts_init_var="$__INTERNAL_opts_init_var +${__INTERNAL_opts_local}$var_name=()" + __INTERNAL_opts_default="$__INTERNAL_opts_default +[[ \"\$optsPresent\" =~ \$(echo \"\<${var_name}\>\") ]] || ${__INTERNAL_opts_local}$var_name='$default'" + case $type in + f) + [[ -z "$2" || -n "$var_name_set" ]] && { + local val=1 + [[ -n "$default" ]] && val='' + optsCode="$optsCode + $var_name+=( '$val' )" + } + __INTERNAL_opts_help="${__INTERNAL_opts_help} + ${opts:1}" + ;; + o|m) + optsCode="$optsCode + shift" + [[ -z "$2" || -n "$var_name_set" ]] && optsCode="$optsCode + $var_name+=( \"\$1\" )" + if [[ "$type" == "o" ]]; then + __INTERNAL_opts_help="${__INTERNAL_opts_help} + ${opts_help:1}" + else + __INTERNAL_opts_help="${__INTERNAL_opts_help} + ${opts:1} ARG" + fi + ;; + esac + [[ -n "$2" ]] && { + optsCode="$optsCode + $2" + } + optsCode="$optsCode + ;;" + + __INTERNAL_opts_help="${__INTERNAL_opts_help}${help:+ + $help +}" + LogMoreMed -f "end" +}; # end of optsAdd }}} + + +# optsBegin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +optsBegin() { + LogMoreMed -f "begin '$*'" + optsCode='' + optsPresent=' ' + __INTERNAL_opts_short='.' + __INTERNAL_opts_long='help' + __INTERNAL_opts_help='' + __INTERNAL_opts_local='' + __INTERNAL_opts_default='' + __INTERNAL_opts_init_var='' + [[ "${FUNCNAME[1]}" != "main" ]] && __INTERNAL_opts_local='local ' + while [[ -n "$1" ]]; do + case $1 in + --) + shift; break + ;; + -h|--help) + shift + __INTERNAL_opts_help="$1" + ;; + *) + echo "unknown option '$1'" + return 1 + ;; + esac + shift; + done + LogMoreMed -f "end" +}; # end of optsBegin }}} + + +# optsDone ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +optsDone() { + LogMoreMed -f "begin '$*'" + optsCode="${__INTERNAL_opts_local}GETOPT=\$(getopt -o ${__INTERNAL_opts_short} -l ${__INTERNAL_opts_long} -- \"\$@\") +[[ \$? -ne 0 ]] && { + echo 'Exiting' + return 1 >& /dev/null + exit 1 +} +eval set -- \"\$GETOPT\" +${__INTERNAL_opts_init_var:1} +while [[ -n \"\$1\" ]]; do + case \$1 in + --) + shift; break + ;; +${optsCode} + + --help) + echo \"\$__INTERNAL_opts_help\" + return >& /dev/null + exit + ;; + *) + echo \"unknown option '\$1'\" + return 1 >& /dev/null + exit 1 + ;; + esac + shift +done +${__INTERNAL_opts_default:1} +unset optsCode __INTERNAL_opts_help __INTERNAL_opts_short __INTERNAL_opts_long __INTERNAL_opts_default __INTERNAL_opts_init_var __INTERNAL_opts_local +" + if ! echo "$optsCode" | grep -q -- '--help$'; then + __INTERNAL_opts_help="$__INTERNAL_opts_help + --help + Show this help." + fi + LogMoreHigh -f "optsCode:\n$optsCode" + LogMoreMed -f "end" +}; # end of optsDone }}} + + +# optsSelfCheck ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +optsSelfCheck() { + optsBegin -h "Usage: $0 [options] + + options: +" +# optsAdd 'help' -f 'echo help' + optsAdd 'flag' -f 'echo f' + optsAdd 'optional|o' -o "echo opt \$1" + optsAdd 'Optional|O' -o "echo opt \$1" --long + optsAdd 'mandatory|m' -m "echo man \$1" + optsDone + + echo "${optsCode}" + + echo ... + + eval "${optsCode}" + + echo ... + + fce() { + optsBegin -h "Usage: $0 [options] + + options: +" + # optsAdd 'help' -f 'echo help' + optsAdd 'flag' -f + optsAdd 'optional|o' -o "echo opt \$1" + optsAdd 'Optional|O' -o "echo opt \$1" --long + optsAdd 'mandatory|m' -m "echo man \$1" + optsDone + echo "${optsCode}" + + echo ... + + eval "${optsCode}" + + echo ... + } + + echo -e 'test for opts in function\n=========================' + fce --help +}; # end of optsSelfCheck }}} + + +# optsLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +optsLibraryLoaded() { + return 0 +}; # end of LogLibraryLoaded }}} + + +echo "done." + +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Dalibor Pospisil + +=back + +=cut + diff --git a/tests/sudoers-options-sanity-test/distribution/Library/tcf/Makefile b/tests/sudoers-options-sanity-test/distribution/Library/tcf/Makefile new file mode 100644 index 0000000..2566969 --- /dev/null +++ b/tests/sudoers-options-sanity-test/distribution/Library/tcf/Makefile @@ -0,0 +1,60 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /distribution/Library/tcf +# Description: Block style coding with ability of skipping parts. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/distribution/Library/tcf +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) lib.sh Makefile + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Block style coding with ability of skipping parts." >> $(METADATA) + @echo "Type: Library" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RhtsRequires: library(distribution/Log)" >> $(METADATA) + @echo "Provides: library(distribution/tcf)" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/sudoers-options-sanity-test/distribution/Library/tcf/lib.sh b/tests/sudoers-options-sanity-test/distribution/Library/tcf/lib.sh new file mode 100644 index 0000000..561b0ff --- /dev/null +++ b/tests/sudoers-options-sanity-test/distribution/Library/tcf/lib.sh @@ -0,0 +1,903 @@ +#!/bin/bash +# try-check-final.sh +# Authors: Dalibor Pospíšil +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# library-prefix = tcf +# library-version = 14 +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +__INTERNAL_tcf_LIB_VERSION=14 +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib library Try-Check-Final + +=head1 DESCRIPTION + +This file contains functions which gives user the ability to define blocks of +code where some of the blocks can be automatically skipped if some of preceeding +blocks failed. + +ATTENTION +This plugin modifies some beakerlib functions! If you suspect that it breakes +some functionality set the environment variable TCF_NOHACK to nonempty value. + +=head1 USAGE + +To use this functionality you need to import library distribution/tcf and add +following line to Makefile. + + @echo "RhtsRequires: library(distribution/tcf)" >> $(METADATA) + +=head1 FUNCTIONS + +=cut + +echo -n "loading library try-check-final v$__INTERNAL_tcf_LIB_VERSION... " + + +let __INTERNAL_tcf_DEBUG_LEVEL_LOW=3 +let __INTERNAL_tcf_DEBUG_LEVEL_MED=$__INTERNAL_tcf_DEBUG_LEVEL_LOW+1 +let __INTERNAL_tcf_DEBUG_LEVEL_HIGH=$__INTERNAL_tcf_DEBUG_LEVEL_LOW+2 + +# global variables {{{ +__INTERNAL_tcf_result=0 +__INTERNAL_tcf_result_file="${BEAKERLIB_DIR:-"/var/tmp"}/tcf.result" +echo -n "$__INTERNAL_tcf_result" > "$__INTERNAL_tcf_result_file" +__INTERNAL_tcf_current_level_data=() +__INTERNAL_tcf_current_level_val=0 +__INTERNAL_tcf_journal=() +#}}} + + +# __INTERNAL_tcf_colorize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_colorize() { + local a + case $1 in + PASS) + a="${__INTERNAL_tcf_color_green}${1}${__INTERNAL_tcf_color_reset}" + ;; + FAIL) + a="${__INTERNAL_tcf_color_red}${1}${__INTERNAL_tcf_color_reset}" + ;; + SKIPPING|WARNING) + a="${__INTERNAL_tcf_color_yellow}${1}${__INTERNAL_tcf_color_reset}" + ;; + BEGIN|INFO) + a="${__INTERNAL_tcf_color_blue}${1}${__INTERNAL_tcf_color_reset}" + ;; + *) + a=$1 + esac + echo -n "$a" +}; # end of __INTERNAL_tcf_colorize }}} + + +# __INTERNAL_tcf_colors_setup ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_colors_setup(){ + T="$TERM" + [[ -t 1 ]] || T="" + [[ -t 2 ]] || T="" + [[ "$1" == "--force" ]] && T="xterm" + case $T in + xterm|screen) + __INTERNAL_tcf_color_black="\e[0;30m" + __INTERNAL_tcf_color_dark_gray="\e[1;30m" + __INTERNAL_tcf_color_blue="\e[0;34m" + __INTERNAL_tcf_color_light_blue="\e[1;34m" + __INTERNAL_tcf_color_green="\e[0;32m" + __INTERNAL_tcf_color_light_green="\e[1;32m" + __INTERNAL_tcf_color_cyan="\e[0;36m" + __INTERNAL_tcf_color_light_cyan="\e[1;36m" + __INTERNAL_tcf_color_red="\e[0;31m" + __INTERNAL_tcf_color_light_red="\e[1;31m" + __INTERNAL_tcf_color_purple="\e[0;35m" + __INTERNAL_tcf_color_light_purple="\e[1;35m" + __INTERNAL_tcf_color_brown="\e[0;33m" + __INTERNAL_tcf_color_yellow="\e[1;33m" + __INTERNAL_tcf_color_light_gray="\e[0;37m" + __INTERNAL_tcf_color_white="\e[1;37m" + __INTERNAL_tcf_color_reset="\e[00m" + ;; + * ) + __INTERNAL_tcf_color_black="" + __INTERNAL_tcf_color_dark_gray="" + __INTERNAL_tcf_color_blue="" + __INTERNAL_tcf_color_light_blue="" + __INTERNAL_tcf_color_green="" + __INTERNAL_tcf_color_light_green="" + __INTERNAL_tcf_color_cyan="" + __INTERNAL_tcf_color_light_cyan="" + __INTERNAL_tcf_color_red="" + __INTERNAL_tcf_color_light_red="" + __INTERNAL_tcf_color_purple="" + __INTERNAL_tcf_color_light_purple="" + __INTERNAL_tcf_color_brown="" + __INTERNAL_tcf_color_yellow="" + __INTERNAL_tcf_color_light_gray="" + __INTERNAL_tcf_color_white="" + __INTERNAL_tcf_color_reset="" + ;; + esac +}; # end of __INTERNAL_tcf_colors_setup +__INTERNAL_tcf_colors_setup; # }}} + + +# __INTERNAL_tcf_copy_function ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_copy_function() { + declare -F $1 > /dev/null || return 1 + eval "$(echo -n "${2}() "; declare -f ${1} | tail -n +2)" +}; # end of __INTERNAL_tcf_copy_function }}} + + +# __INTERNAL_tcf_addE2R ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_addE2R() { + __INTERNAL_tcf_copy_function $1 TCF_orig_$1 + eval "${1}() { TCF_orig_${1} \"\$@\"; tcfE2R; }" +}; # end of __INTERNAL_tcf_addE2R }}} + + +# __INTERNAL_tcf_insertE2R ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_insertE2R() { + __INTERNAL_tcf_copy_function $1 TCF_orig_$1 + eval "$(echo -n "${1}() "; declare -f ${1} | tail -n +2 | sed -e 's/\(.*__INTERNAL_ConditionalAssert.*\)/\1\ntcfE2R;/')" +}; # end of __INTERNAL_tcf_insertE2R }}} + + +# __INTERNAL_tcf_get_current_level ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_get_current_level() { + local l=$__INTERNAL_tcf_current_level_val + if [[ $1 ]]; then + l=$(($l+$1)) + fi + local i + for i in $(seq 1 $(($l*2)) ); do echo -n " "; done + return $l +}; # end of __INTERNAL_tcf_get_current_level }}} + + +# __INTERNAL_tcf_incr_current_level ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_incr_current_level() { + let __INTERNAL_tcf_current_level_val++ + __INTERNAL_Log_prefix=$(__INTERNAL_tcf_get_current_level) +}; # end of __INTERNAL_tcf_incr_current_level }}} + + +# __INTERNAL_tcf_decr_current_level ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_decr_current_level() { + let __INTERNAL_tcf_current_level_val-- + __INTERNAL_Log_prefix=$(__INTERNAL_tcf_get_current_level) +}; # end of __INTERNAL_tcf_decr_current_level }}} + + +# __INTERNAL_tcf_do_hack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_do_hack() { + LogDebug "TCF_NOHACK='$TCF_NOHACK'" + if [[ -z "$TCF_NOHACK" ]]; then + tcfChk "Apply TCF beakerlib hacks" && { + rlLog " injecting tcf hacks into the beakerlib functions" + echo -n "patching rlLog" + local rlL=$(declare -f rlLog | sed -e 's|\] ::|\0${__INTERNAL_Log_prefix}|;s|$3 $1"|${3:+"$3 "}$1"|') + eval "$rlL" + + echo -n ", rljAddTest" + __INTERNAL_tcf_copy_function rljAddTest __INTERNAL_tcf_orig_rljAddTest + true; rljAddTest() { + local a="${__INTERNAL_Log_prefix}$1"; shift + [[ "$1" != "FAIL" ]]; tcfE2R + __INTERNAL_tcf_journal=("${__INTERNAL_tcf_journal[@]}" "$1" "$a") + __INTERNAL_tcf_orig_rljAddTest "$a" "$@" + } + echo -n ", rljAddMessage" + __INTERNAL_tcf_copy_function rljAddMessage __INTERNAL_tcf_orig_rljAddMessage + true; rljAddMessage() { + local a="${__INTERNAL_Log_prefix}$1"; shift + __INTERNAL_tcf_journal=("${__INTERNAL_tcf_journal[@]}" "$1" "$a") + __INTERNAL_tcf_orig_rljAddMessage "$a" "$@" + } + echo -n ", __INTERNAL_LogAndJournalFail" + __INTERNAL_tcf_copy_function __INTERNAL_LogAndJournalFail __INTERNAL_tcf_orig___INTERNAL_LogAndJournalFail + true; __INTERNAL_LogAndJournalFail() { + tcfNOK + __INTERNAL_tcf_orig___INTERNAL_LogAndJournalFail "$@" + } + echo "." + tcfFin --no-assert --ignore; } + else + Log "skip hacking beakerlib functions" + fi +}; # end of __INTERNAL_tcf_do_hack }}} + + +# __INTERNAL_tcf_kill_old_plugin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_kill_old_plugin() { + tcfChk "Get rid of the old TCF implementation. removing" && { + local comma='' i + for i in Try Chk Fin E2R RES OK NOK NEG TCFcheckFinal TCFreport; do + echo -n "${comma}rl$i" + unset -f rl$i + comma=', ' + done + echo '.' + tcfFin --no-assert; } +}; # end of __INTERNAL_tcf_kill_old_plugin }}} + + +: <<'=cut' +=pod + +=head2 Block functions + +=cut + +# __INTERNAL_tcf_parse_params ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +__INTERNAL_tcf_parse_params() { + local GETOPT=$(getopt -q -o if: -l ignore,no-assert,fail-tag: -- "$@") + eval set -- "$GETOPT" + echo "local ignore noass title fail_tag" + echo "[ -z \"\$ignore\" ] && ignore=0" + echo "[ -z \"\$noass\" ] && noass=0" + echo "[ -z \"\$fail_tag\" ] && fail_tag='FAIL'" + while [[ -n "$@" ]]; do + case $1 in + --) + shift; break + ;; + --ignore|-i) + echo "ignore=1" + echo "noass=1" + ;; + --no-assert|-n) + echo "noass=1" + ;; + --fail-tag|-f) + shift + echo "fail_tag='$1'" + ;; + *) + echo "unknown option $1" + return 1 + ;; + esac + shift; + done + [[ -n "$1" ]] && echo "title=\"${1}\"" + echo "eval set -- \"$(echo "$GETOPT" | sed -e 's/.*-- //')\"" +}; # end of __INTERNAL_tcf_parse_params }}} + + +# tcfTry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfTry + +Starting function of block which will be skipped if an error has been detected +by tcfFin function occurent before. + + tcfTry ["title"] [-i|--ignore] [--no-assert] [--fail-tag TAG] && { + + tcfFin; } + +If title is omitted than noting is printed out so no error will be reported (no +Assert is executed) thus at least the very top level tcfTry should have title. + +tcfTry and tcfChk blocks are stackable so you can organize them into a hierarchy +structure. + +Note that tcfFin has to be used otherwise the overall result will not be +accurate. + +=over + +=item title + +Text which will be displayed and logged at the beginning and the end (in tcfFin +function) of the block. + +=item -i, --ignore + +Do not propagate the actual result to the higher level result. + +=item -n, --no-assert + +Do not log error into the journal. + +=item -f, --fail-tag TAG + +If the result of the block is FAIL, use TAG instead ie. INFO or WARNING. + +=back + +Returns 1 if and error occured before, otherwise returns 0. + +=cut + +tcfTry() { + LogMoreLow -f "begin '$*'" + local vars=$(__INTERNAL_tcf_parse_params "$@") || { Log "$vars" FAIL; return 1; } + LogMoreMed -f "vars:\n$vars" + LogMoreLow -f "evaluating options start" + eval "$vars" + LogMoreLow -f "evaluating options end" + local incr= + local pp="SKIPPING" + tcfRES; # to set __INTERNAL_tcf_result + LogMoreLow -f "result was $__INTERNAL_tcf_result" + if [[ $__INTERNAL_tcf_result -eq 0 ]]; then + __INTERNAL_tcf_current_level_data=("$__INTERNAL_tcf_result" "$vars" "${__INTERNAL_tcf_current_level_data[@]}") + pp="BEGIN" + incr=1 + fi + if [[ -n "$title" ]]; then + Log "$title" "$pp" + [[ -n "$incr" ]] && { + LogMoreLow -f "increment indentation level" + __INTERNAL_tcf_incr_current_level + } + fi + LogMoreLow -f "end" + return $__INTERNAL_tcf_result +}; # end of tcfTry }}} + + +# tcfChk ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfChk + +Starting function of block which will be always executed. + + tcfChk ["title"] [-i|--ignore] [--no-assert] [--fail-tag TAG] && { + + tcfFin; } + +If title is omitted than noting is printed out so no error will be reported (no +Assert is executed) thus at least the very top level tcfChk should have title. + +tcfTry and tcfChk blocks are stackable so you can organize them into a hierarchy +structure. + +Note that tcfFin has to be used otherwise the overall result will not be +accurate. + +For details about arguments see tcfTry. + +Returns 0. + +=cut + +tcfChk() { + LogMoreLow -f "begin '$*'" + tcfRES; # to set __INTERNAL_tcf_result + local res=$__INTERNAL_tcf_result + tcfRES 0 + tcfTry "$@" + __INTERNAL_tcf_current_level_data[0]=$res + LogMoreLow -f "end" + return $__INTERNAL_tcf_result +}; # end of tcfChk }}} + + +# tcfFin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfFin + +Ending function of block. It does some evaluation of previous local and global +results and puts it into the global result. + + tcfTry ["title"] && { + + tcfFin [-i|--ignore] [--no-assert] [--fail-tag TAG]; } + +Local result is actualy exit code of the last command int the body. + +Global result is an internal varibale hodning previous local results. +Respectively last error or 0. + +For details about arguments see tcfTry. + +Returns local result of the preceeding block. + +=cut + +tcfFin() { + local RES=$? + LogMoreLow -f "begin '$*'" + LogMoreMed -f "previous exit code was '$RES'" + local vars=$(__INTERNAL_tcf_parse_params "$@") || { Log "$vars" FAIL; return 1; } + LogMoreMed -f "vars:\n$vars" + LogMoreLow -f "evaluating options start" + eval "$vars" + LogMoreLow -f "evaluating options end" + tcfRES; # to set __INTERNAL_tcf_result + [[ $RES -ne 0 ]] && tcfRES $RES + RES=$__INTERNAL_tcf_result + LogMoreMed -f "overall result is '$RES'" + LogMoreMed -f "data:\n${__INTERNAL_tcf_current_level_data[1]}" + LogMoreLow -f "evaluating data start" + eval "${__INTERNAL_tcf_current_level_data[1]}" + LogMoreLow -f "evaluating data end" + if [[ -n "$title" ]]; then + __INTERNAL_tcf_decr_current_level + if [[ $ignore -eq 1 ]]; then + RES=0 + [[ $__INTERNAL_tcf_result -ne 0 ]] && title="$title - ignored" + fi + if [[ $noass -eq 0 ]]; then + tcfAssert0 "$title" $__INTERNAL_tcf_result "$fail_tag" + else + if [[ $__INTERNAL_tcf_result -eq 0 ]]; then + local pp="PASS" + LogInfo "$title - $pp" + else + local pp="${fail_tag:-FAIL}" + LogWarn "$title - $pp" + fi + fi + fi + if [[ $__INTERNAL_tcf_result -eq 0 || $ignore -eq 1 ]]; then + tcfRES ${__INTERNAL_tcf_current_level_data[0]} + fi + local i + for i in 0 1; do unset __INTERNAL_tcf_current_level_data[$i]; done + __INTERNAL_tcf_current_level_data=("${__INTERNAL_tcf_current_level_data[@]}") + LogMoreLow -f "end" + return $RES +}; # end of tcfFin }}} + +: <<'=cut' +=pod + +=head2 Functions for manipulation with the results + +=cut + + +# tcfRES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfRES + +Sets and return the global result. + + tcfRES [-p|--print] [number] + +=over + +=item -p --print + +Also print the result value. + +=item number + +If present the global result is set to this value. + +=back + +Returns global result. + +=cut + +tcfRES() { + local p=0 + while [[ -n "$1" ]]; do + case $1 in + --print|-p) + p=1 + ;; + *) + break + ;; + esac + shift + done + if [[ -n "$1" ]]; then + __INTERNAL_tcf_result=$1 + echo -n "$__INTERNAL_tcf_result" > "$__INTERNAL_tcf_result_file" + else + __INTERNAL_tcf_result="$(cat "$__INTERNAL_tcf_result_file")" + fi + [[ $p -eq 1 ]] && echo $__INTERNAL_tcf_result + return $__INTERNAL_tcf_result +}; # end of tcfRES }}} + + +# tcfOK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfOK + +Sets the global result to 0. + + tcfOK + +Returns global result. + +=cut + +tcfOK() { + tcfRES 0 +}; # end of tcfOK }}} + + +# tcfNOK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfNOK + +Sets the global result to 1 or given number. + + tcfNOK [number] + +=over + +=item number + +If present the global result is set to this value. + +=back + +Returns global result. + +=cut + +tcfNOK() { + if [[ -n "$1" ]]; then + [[ $1 -eq 0 ]] && echo "You have requested result '0'. You should use tcfOK instead." + tcfRES $1 + else + tcfRES 1 + fi +}; # end of tcfNOK }}} + + +# tcfE2R ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfE2R + +Converts exit code of previous command to local result if the exit code is not 0 +(zero). + + + tcfE2R [number] + +=over + +=item number + +If present use it instead of exit code. + +=back + +Returns original exit code or given number. + +=cut + +tcfE2R() { + local res=$? + [[ -n "$1" ]] && res=$1 + [[ $res -ne 0 ]] && tcfRES $res + return $res +}; # end of tcfE2R }}} + + +: <<'=cut' +=pod + +=head2 Functions for manipulation with the exit codes + +=cut + + +# tcfNEG ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfNEG + +Negates exit code of previous command. + + + tcfNEG + +Returns 1 if original exit code was 0, otherwise returns 0. + +=cut + +tcfNEG() { + [[ $? -eq 0 ]] && return 1 || return 0 +}; # end of tcfNEG }}} + + +# tcfRun ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfRun + +Simmilar to rlRun but it also annouces the beginnign of the command. + + tcfRun [--fail-tag|-f TAG] command [exp_result [title]] + +Moreover if 'command not found' appears on STDERR it should produce WARNING. + +=over + +=item command + +Command to execute. + +=item exp_result + +Specification of expect resutl. + +It can be a list of values or intervals or * for any result. Also negation (!) can be used. + + Example: + + <=2,7,10-12,>252,!254 means following values 0,1,2,7,10,11,12,253,255 + +=item title + +Text which will be displayed and logged at the beginning and the end of command execution. + +=item --fail-tag | -f + +If the command fails use TAG instead of FAIL. + +=back + +Returns exit code of the executed command. + +=cut + +tcfRun() { + LogMore_ -f "begin $*" + optsBegin + optsAdd 'fail-tag|f' --mandatory + optsAdd 'timeout' --optional 'timeout="${1:-10}"' + optsAdd 'kill-timeout|kt' --mandatory --default 5 + optsAdd 'signal' --mandatory --default TERM + optsAdd 'check-code' --mandatory --default 'kill -0 $cmdpid >&/dev/null' + optsAdd 'kill-code' --mandatory --default '/bin/kill -$signal -- $cmdpid' + optsAdd 'allow-skip|as' --flag + optsAdd 'no-assert|n' --flag + optsDone; eval "${optsCode}" + LogMore_ -f "after opts $*" + [[ -z "$allowskip" ]] && tcfChk + local orig_expecode="${2:-0}" + local expecode="$orig_expecode" + [[ "$expecode" == "*" ]] && expecode="0-255" + local command="$1" + local comment="Running command '$command'" + [[ -n "$3" ]] && comment="$3" + [[ -n "$expecode" ]] && { + expecode=$(echo "$expecode" | tr ',-' '\n ' | sed -e 's/^!=/!/;s/^=//;s/^<=\(.\+\)$/0 \1/;s/^>=\(.\+\)$/\1 255/;s/^<\(.\+\)$/0 \$(( \1 - 1 ))/;s/^>\(.\+\)$/\$(( \1 + 1 )) 255/' | while read line; do [[ "$line" =~ ^[^\ ]+$ ]] && echo "$line" || eval seq $line; done; ) + tcfE2R + LogMoreLow -f "orig_expecode='$orig_expecode'" + LogMoreLow -f "expecode='$expecode'" + } + tcfTry ${noassert:+--no-assert} "$comment" && { + local errout=$(mktemp) + LogMoreLow -f "executing '$command'" + if [[ "$optsPresent" =~ $(echo "\") ]]; then + LogDebug -f "using watchdog feature" + local ec="$(mktemp)" + eval "$command; echo $? > $ec 2> >(tee $errout)" & + local cmdpid=$! + local time_start=$(date +%s) + local timeout_t=$(( $time_start + $timeout )) + while true; do + if ! eval "$checkcode"; then + Log "command finished in $(($(date +%s) - $time_start )) seconds" + local res="$(cat $ec)" + break + elif [[ $(date +%s) -ge $timeout_t ]]; then + echo + Log "command is still running, sending $signal signal" + eval "$killcode" + tcfNOK 255 + echo 255 > $ec + let timeout_t+=killtimeout + signal=KILL + fi + sleep 0.1 + done + rm -f $ec + else + eval "$command" 2> >(tee $errout) + local res=$? + fi + LogMoreLow -f "got '$res'" + local resmatch=$(echo "$expecode" | grep "^\!\?${res}$") + LogMoreLow -f "resmatch='$resmatch'" + [[ -n "$resmatch" && ! "$resmatch" =~ '!' ]] + if tcfE2R; then + ! grep -iq "command not found" $errout || { failtag='WARNING'; tcfNOK; } + else + Log "Expected result was '$orig_expecode', got '$res'!" + fi + tcfFin ${failtag:+--fail-tag "$failtag"}; } + rm -f $errout + [[ -z "$allowskip" ]] && tcfFin + LogMore_ -f "end $*" + return $res +}; # end of tcfRun }}} + + +: <<'=cut' +=pod + +=head2 Functions for logging + +=cut + + +# tcfAssert0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +tcfAssert0() { + LogMoreLow -f "begin '$*'" + local RES="${3:-FAIL}" + [[ $2 -eq 0 ]] && RES='PASS' + Log "$1" $RES + LogMoreLow -f "end" +}; # end of tcfAssert0 }}} + + +# tcfCheckFinal ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +: <<'=cut' +=pod + +=head3 tcfCheckFinal + +Check that all tcfTry / tcfChk functions have been close by tcfFin. + + tcfCheckFinal + +=cut + +tcfCheckFinal() { + tcfAssert0 "Check that TCF block cache is empty" ${#__INTERNAL_tcf_current_level_data[@]} + tcfAssert0 "Check that TCF current level is 0" $__INTERNAL_tcf_current_level_val +}; # end of tcfCheckFinal }}} + + +echo "done." + +: <<'=cut' +=pod + +=head2 Self check functions + +=cut + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# tcfSelfCheck {{{ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +: <<'=cut' +=pod + +=head3 tcfSelfCheck + +Does some basic functionality tests. + + tcfSelfCheck + +The function is called also by the following command: + + ./lib.sh selfcheck + +=cut + + +tcfSelfCheck() { + tcfChk "check 1" &&{ + tcfTry "try 1.1 - true" &&{ + true + tcfFin;} + tcfTry "try 1.2 - false" &&{ + false + tcfFin;} + tcfTry "try 1.3 - true" &&{ + true + tcfFin;} + tcfFin;} + tcfChk "check 2" &&{ + tcfTry "try 2.1 - true" &&{ + true + tcfFin;} + tcfTry "try 2.2 - true - ignore" &&{ + true + tcfFin -i;} + tcfTry "try 2.3 - true" &&{ + true + tcfFin;} + tcfFin;} + tcfChk "check 3" &&{ + tcfTry "try 3.1 - true" &&{ + true + tcfFin;} + tcfTry "try 3.2 - false - ignore" &&{ + false + tcfFin -i;} + tcfTry "try 3.3 - true" &&{ + true + tcfFin;} + tcfFin;} + tcfCheckFinal + tcfAssert0 "Overall result" $(tcfRES -p) + LogReport +} +if [[ "$1" == "selfcheck" ]]; then + tcfSelfCheck +fi; # end of tcfSelfCheck }}} + + +# tcfLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +tcfLibraryLoaded() { + rlImport distribution/Log + declare -F rlDie > /dev/null && { + #rlJournalStart + #rlPhaseStartSetup "TCF" + echo -e "\nrunning inside the beakerlib - using rlAssert0" + true; tcfAssert0() { + local text="$1" + [[ "$3" != "FAIL" && "$3" != "PASS" ]] && text="$text - $3" + __INTERNAL_ConditionalAssert "$text" "$2" + } + __INTERNAL_tcf_do_hack + #rlPhaseEnd + #rlJournalEnd + }; + if declare -F rlE2R >& /dev/null; then + __INTERNAL_tcf_kill_old_plugin + fi + true +}; # end of tcfLibraryLoaded }}} + + +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Dalibor Pospisil + +=back + +=cut + + diff --git a/tests/sudoers-options-sanity-test/distribution/Library/testUser/Makefile b/tests/sudoers-options-sanity-test/distribution/Library/testUser/Makefile new file mode 100644 index 0000000..037162e --- /dev/null +++ b/tests/sudoers-options-sanity-test/distribution/Library/testUser/Makefile @@ -0,0 +1,60 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /distribution/Library/testUser +# Description: Block style coding with ability of skipping parts. +# Author: Dalibor Pospisil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/distribution/Library/testUser +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) lib.sh Makefile + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Dalibor Pospisil " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Setup/cleanup standard testing user." >> $(METADATA) + @echo "Type: Library" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RhtsRequires: library(distribution/Log)" >> $(METADATA) + @echo "Provides: library(distribution/testUser)" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/sudoers-options-sanity-test/distribution/Library/testUser/lib.sh b/tests/sudoers-options-sanity-test/distribution/Library/testUser/lib.sh new file mode 100644 index 0000000..24da7a6 --- /dev/null +++ b/tests/sudoers-options-sanity-test/distribution/Library/testUser/lib.sh @@ -0,0 +1,234 @@ +#!/bin/bash +# try-check-final.sh +# Authors: Dalibor Pospíšil +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2012 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# library-prefix = testUser +# library-version = 7 +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib library testUser + +=head1 DESCRIPTION + +This library provide s function for maintaining testing users. + +=head1 USAGE + +To use this functionality you need to import library distribution/testUser and add +following line to Makefile. + + @echo "RhtsRequires: library(distribution/testUser)" >> $(METADATA) + +=head1 VARIABLES + +=over + +=item testUser + +Array of testing user login names. + +=item testUserPasswd + +Array of testing users passwords. + +=item testUserUID + +Array of testing users UIDs. + +=item testUserGID + +Array of testing users primary GIDs. + +=item testUserGroup + +Array of testing users primary group names. + +=item testUserGIDs + +Array of space separated testing users all GIDs. + +=item testUserGroups + +Array of space separated testing users all group names. + +=item testUserGecos + +Array of testing users gecos fields. + +=item testUserHomeDir + +Array of testing users home directories. + +=item testUserShell + +Array of testing users default shells. + +=back + +=head1 FUNCTIONS + +=cut + +echo -n "loading library testUser... " + +: <<'=cut' +=pod + +=head3 testUserSetup, testUserCleanup + +Creates/removes testing user(s). + + rlPhaseStartSetup + testUserSetup [NUM] + rlPhaseEnd + + rlPhaseStartCleanup + testUserCleanup + rlPhaseEnd + +=over + +=item NUM + +Optional number of user to be created. If not specified one user is created. + +=back + +Returns 0 if success. + +=cut + + +testUserSetup() { + # parameter dictates how many users should be created, defaults to 1 + local res=0 + local count_created=0 + local count_wanted=${1:-"1"} + local index=0 + (( $count_wanted < 1 )) && return 1 + + while (( $count_created != $count_wanted ));do + let index++ + local newUser="testuser${index}" + local newUserPasswd="redhat" + id "$newUser" &> /dev/null && continue # if user with the name exists, try again + + # create + useradd -m $newUser >&2 || ((res++)) + echo "$newUserPasswd" | passwd --stdin $newUser || ((res++)) + + # save the users array + testUser+=($newUser) + testUserPasswd+=($newUserPasswd) + set | grep "^testUser=" > $__INTERNAL_testUser_users_file + set | grep "^testUserPasswd=" >> $__INTERNAL_testUser_users_file + ((count_created++)) + done + __INTERNAL_testUserRefillInfo || ((res++)) + + echo ${res} + [[ $res -eq 0 ]] +} + + +__INTERNAL_testUserRefillInfo() { + local res=0 + local user + testUserUID=() + testUserGID=() + testUserGroup=() + testUserGIDs=() + testUserGroups=() + testUserGecos=() + testUserHomeDir=() + testUserShell=() + + for user in ${testUser[@]}; do + local ent_passwd=$(getent passwd ${user}) || ((res++)) + local users_id="$(id ${user})" || ((res++)) + # testUser is filled during user creation - already present + # testUserPasswd is saved same way as testUser - already present + testUserUID+=("$(echo "$ent_passwd" | cut -d ':' -f 3)") + testUserGID+=("$(echo "$ent_passwd" | cut -d ':' -f 4)") + testUserGroup+=("$(echo "$users_id" | sed -r 's/.*gid=(\S+).*/\1/;s/[[:digit:]]+\(//g;s/\)//g;s/,/ /g')") + testUserGIDs+=("$(echo "$users_id" | sed -r 's/.*groups=(\S+).*/\1/;s/\([^\)]+\)//g;s/\)//g;s/,/ /g')") + testUserGroups+=("$(echo "$users_id" | sed -r 's/.*groups=(\S+).*/\1/;s/[[:digit:]]+\(//g;s/\)//g;s/,/ /g')") + testUserGecos+=("$(echo "$ent_passwd" | cut -d ':' -f 5)") + testUserHomeDir+=("$(echo "$ent_passwd" | cut -d ':' -f 6)") + testUserShell+=("$(echo "$ent_passwd" | cut -d ':' -f 7)") + done + + echo ${res} + [[ $res -eq 0 ]] +} + + +testUserCleanup() { + local res=0 + for user in ${testUser[@]}; do + userdel -rf "$user" >&2 || ((res++)) + done + unset testUser + __INTERNAL_testUserRefillInfo + rm -f $__INTERNAL_testUser_users_file >&2 || ((res++)) + + echo ${res} + [[ $res -eq 0 ]] +} + + + +# testUserLibraryLoaded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {{{ +testUserLibraryLoaded() { + local res=0 + # necessary init steps + __INTERNAL_testUser_users_file="$BEAKERLIB_DIR/users" + + # try to fill in users array with previous data + [[ -f ${__INTERNAL_testUser_users_file} ]] && . ${__INTERNAL_testUser_users_file} >&2 + __INTERNAL_testUserRefillInfo >&2 || ((res++)) + + [[ $res -eq 0 ]] +}; # end of testUserLibraryLoaded }}} + + +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Dalibor Pospisil + +=back + +=cut + +echo "done." + diff --git a/tests/sudoers-options-sanity-test/runtest.sh b/tests/sudoers-options-sanity-test/runtest.sh new file mode 100755 index 0000000..b24299f --- /dev/null +++ b/tests/sudoers-options-sanity-test/runtest.sh @@ -0,0 +1,379 @@ +#!/bin/bash +# vim: dict=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# runtest.sh of /CoreOS/sudo/Sanity/sudoers-options-sanity-test +# Description: This sanity test checks pre-defined (some are commented) options (examples) in sudoers file. +# Author: Ales Marecek +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2013 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include Beaker environment +. /usr/bin/rhts-environment.sh || exit 1 +. /usr/share/beakerlib/beakerlib.sh || exit 1 + +rlJournalStart && { + rlPhaseStartSetup && { + [[ -z "$BEAKERLIB_LIBRARY_PATH" ]] && BEAKERLIB_LIBRARY_PATH="$(dirname "$(readlink -f "$0")")" + rlRun "rlImport --all" 0 "Import libraries" || rlDie "cannot continue" + tcfTry "Setup phase" && { + tcfRun "rlCheckMakefileRequires" + rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory" + CleanupRegister "rlRun 'rm -r $TmpDir' 0 'Removing tmp directory'" + CleanupRegister 'rlRun "popd"' + rlRun "pushd $TmpDir" + CleanupRegister 'rlRun "rlFileRestore"' + rlRun "rlFileBackup --clean /etc/sudoers" + rpm -V sudo | grep /etc/sudoers && { + # we need clean config file that is shipped with package + rlRun "rm -rf /etc/sudoers" + rlRun "yum -y reinstall sudo" 0 "Reinstalling '${PACKAGE}' package" + }; : + CleanupRegister 'rlRun "testUserCleanup"' + rlRun "testUserSetup 2" + tcfFin; } + rlPhaseEnd; } + + tcfTry "Tests" --no-assert && { + rlPhaseStartTest "Active options test - active sudo settings" && { + if ( rlIsRHEL 6 && rlIsRHEL '>=6.8' ) || ( rlIsRHEL 7 && rlIsRHEL '>=7.3' ); then + _OPTIONS=("!visiblepw" "always_set_home" "env_reset") + elif rlIsRHEL; then + _OPTIONS=("requiretty" "!visiblepw" "always_set_home" "env_reset") + else + if rlIsFedora 20; then + _OPTIONS=("requiretty" "env_reset") + else + _OPTIONS=("!visiblepw" "env_reset") + fi + fi + for _OPTION in ${_OPTIONS[@]}; do + rlRun "grep '^Defaults\s\+${_OPTION}' /etc/sudoers" 0 "Test: '${_OPTION}' check" + done + rlPhaseEnd; } + + rlPhaseStartTest "Active options test - Evironment" && { + for _OPTION in DISPLAY HOSTNAME USERNAME LC_COLLATE LC_MESSAGES LC_TIME LC_ALL XAUTHORITY; do + rlRun "cat /etc/sudoers | grep '^Defaults\s\+env_keep' | grep '${_OPTION}'" 0 "Test: '${_OPTION}' check" + done + rlRun "grep '^Defaults\s\+secure_path\s\+=\s\+/sbin:/bin:/usr/sbin:/usr/bin' /etc/sudoers" 0 "Test: 'secure_path' check" + rlPhaseEnd; } + + rlPhaseStartTest "Commented options test - examples" && { + for _OPTION in "Host_Alias" "Cmnd_Alias" "User_Alias"; do + rlRun "grep \"^#.*${_OPTION}.*\" /etc/sudoers" 0 "Test: '${_OPTION}' check" + done + rlPhaseEnd; } + + rlPhaseStartTest "pam_service and pam_login_service" && { + CleanupRegister --mark 'rlRun "rlFileRestore --namespace pam_service"' + rlRun "rlFileBackup --namespace pam_service --clean /etc/pam.d/ /etc/sudoers" + rlRun "cat /etc/pam.d/sudo > /etc/pam.d/sudo2" + rlRun "cat /etc/pam.d/sudo-i > /etc/pam.d/sudo2-i" + rlRun "sed -i '/session.*pam_echo/d' /etc/pam.d/sudo" + rlRun "sed -i '/session.*pam_echo/d' /etc/pam.d/sudo-i" + rlRun "echo -e 'session\toptional\tpam_echo.so %%sudo pam_service' >> /etc/pam.d/sudo" + rlRun "echo -e 'session\toptional\tpam_echo.so %%sudo-i pam_login_service' >> /etc/pam.d/sudo-i" + rlRun "echo -e 'session\toptional\tpam_echo.so %%sudo2 pam_service' >> /etc/pam.d/sudo2" + rlRun "echo -e 'session\toptional\tpam_echo.so %%sudo2-i pam_login_service' >> /etc/pam.d/sudo2-i" + sudoers_file="$(cat /etc/sudoers)" + rlRun -s "sudo id" + rlAssertGrep '^%sudo pam_service' $rlRun_LOG + rm -f $rlRun_LOG + rlRun -s "sudo -i id" + rlAssertGrep '^%sudo-i pam_login_service' $rlRun_LOG + rm -f $rlRun_LOG + tcfChk "change pam service name" && { + echo "Defaults pam_service=sudo2" > /etc/sudoers + echo "Defaults pam_login_service=sudo2-i" >> /etc/sudoers + echo "$sudoers_file" >> /etc/sudoers + tcfFin; } + rlRun -s "sudo id" + rlAssertGrep '^%sudo2 pam_service' $rlRun_LOG + rm -f $rlRun_LOG + rlRun -s "sudo -i id" + rlAssertGrep '^%sudo2-i pam_login_service' $rlRun_LOG + rm -f $rlRun_LOG + CleanupDo --mark + rlPhaseEnd; } + + rlPhaseStartTest "User and Group settings" && { + rlRun "grep '^root\s\+ALL=(ALL)\s\+ALL' /etc/sudoers" 0 "Test: 'root' user check" + # specific "%wheel" command in RHEL-7 - allowing "wheel" group for super-trooper admin-needs by Anaconda + rlIsRHEL 4 5 6 + [ $? -eq 0 ] && rlRun "grep '^#.*%wheel\s\+ALL=(ALL)\s\+ALL' /etc/sudoers" 0 "Test: 'wheel' (commented) group check" || rlRun "grep '^%wheel\s\+ALL=(ALL)\s\+ALL' /etc/sudoers" 0 "Test: 'wheel' group check" + rlRun "grep '^#.*%sys' /etc/sudoers" 0 "Test: 'sys' (commented) group check" + rlPhaseEnd; } + + ! rlIsRHEL '<6' && rlPhaseStartTest 'env_check' && { + tcfChk "env_check" && { + tcfChk "setup phase" && { + rlRun "cat /etc/sudoers > sudoers" + CleanupRegister " + rlRun 'cat sudoers > /etc/sudoers' + rlRun \"export TZ='${TZ}'\" + " + clean_sudoers=$CleanupRegisterID + rlRun "echo 'Defaults env_check += \"TZ\"' >> /etc/sudoers" + rlRun "echo 'Defaults env_keep += \"TZ\"' >> /etc/sudoers" + rlRun "echo 'Defaults !authenticate' >> /etc/sudoers" + rlRun "sed -ri 's/(Defaults\s+)(requiretty)/\1!\2/' /etc/sudoers" + rlRun "cat -n /etc/sudoers | tr '\t' ' ' | grep -Pv '^ +[0-9]+ +(#|$)'" + tcfFin; } + tcfTry "test" && { + tcfChk "test allowed values" && { + for TZ in AB America/New_York /usr/share/zoneinfo/America/New_York; do + rlRun "export TZ='$TZ'" + rlRun -s "env" + rlAssertGrep "^TZ=$TZ" $rlRun_LOG + rm -f $rlRun_LOG + rlRun -s "sudo env" + rlAssertGrep "^TZ=$TZ" $rlRun_LOG + rm -f $rlRun_LOG + done + tcfFin; } + tcfChk "test wrong values" && { + for TZ in "A B" \ + /etc/hosts \ + /usr/share/zoneinfo/../zoneinfo/America/New_York \ + 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 \ + ; do + rlRun "export TZ='$TZ'" + rlRun -s "env" + rlAssertGrep "^TZ=$TZ" $rlRun_LOG + rm -f $rlRun_LOG + rlRun -s "sudo env" + rlAssertNotGrep "^TZ=$TZ" $rlRun_LOG + rm -f $rlRun_LOG + done + tcfFin; } + tcfFin; } + tcfChk "cleanup phase" && { + CleanupDo $clean_sudoers + tcfFin; } + tcfFin; } + rlPhaseEnd; } + + rlPhaseStartTest "test, requiretty" && { + tcfChk && { + tcfChk "setup" && { + CleanupRegister --mark 'rlRun "rlFileRestore --namespace requiretty"' + rlRun "rlFileBackup --clean --namespace requiretty /etc/sudoers" + rlRun "echo '$testUser ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers" + tcfFin; } + + tcfTry && { + tcfChk "test, requiretty" && { + rlRun "sed -i '/requiretty/d' /etc/sudoers" + rlRun "echo 'Defaults requiretty' >> /etc/sudoers" + rlRun -s "nohup su -l -c 'sudo id' $testUser > /dev/stdout" 1 + rlAssertGrep 'you must have a tty' $rlRun_LOG + rm -f $rlRun_LOG + tcfFin; } + + tcfChk "test, !requiretty" && { + rlRun "sed -i '/requiretty/d' /etc/sudoers" + rlRun "echo 'Defaults !requiretty' >> /etc/sudoers" + rlRun "nohup su -l -c 'sudo id' $testUser > /dev/stdout" + tcfFin; } + tcfFin; } + + tcfChk "cleanup" && { + CleanupDo --mark + tcfFin; } + tcfFin; } + rlPhaseEnd; } + + if ! rlIsRHEL '<7.4'; then + rlPhaseStartTest "test, iolog" && { + tcfChk && { + iolog_config() { + rlLog "create config" + cat > /etc/sudoers.d/iolog < /etc/sudoers.d/test <& /dev/null && { + postsuper -d ALL + } + [[ -e /var/spool/mqueue/ ]] && [[ -n "$(ls -1 /var/spool/mqueue/)" ]] && { + rm -rf /var/spool/mqueue/* + } + [[ -e /var/spool/clientmqueue/ ]] && [[ -n "$(ls -1 /var/spool/clientmqueue/)" ]] && { + rm -rf /var/spool/clientmqueue/* + } + [[ -e /var/spool/postfix/maildrop/ ]] && [[ -n "$(ls -1 /var/spool/postfix/maildrop/)" ]] && { + rm -rf /var/spool/postfix/maildrop/* + } + } + get_last_mail_log() { + sleep 1 + tail -n +$(($last_line_num + 1)) /var/log/maillog | grep -iv 'connection timed out' > last_mail.log + mailq >> last_mail.log + mailq -Ac >> last_mail.log + rlRun "cat last_mail.log" 0-255 + clean_mail_queue + last_line_num=`cat /var/log/maillog | wc -l` + } + tcfChk "setup" && { + CleanupRegister --mark 'rlRun "rlFileRestore --namespace MAIL"' + rlRun "rlFileBackup --clean --namespace MAIL /etc/sudoers.d/test" + clean_mail_queue + get_last_mail_log + tcfFin; } + + tcfTry "test" && { + + tcfChk "test, mail_always test" && { + create_config mail_always + rlRun "su -c 'sudo /bin/ls /' - $testUser" 0 + get_last_mail_log + rlAssertGrep 'emailto@domain.com' last_mail.log -iq + tcfFin; } + + tcfChk "test, NOMAIL test" && { + create_config mail_always NOMAIL: + last_line_num=`cat /var/log/maillog | wc -l` + rlRun "su -c 'sudo /bin/ls /' - $testUser" 0 + get_last_mail_log + rlAssertNotGrep 'emailto@domain.com' last_mail.log -iq + rlRun "su -c 'sudo /bin/ls /' - ${testUser[1]}" 0 + get_last_mail_log + rlAssertGrep 'emailto@domain.com' last_mail.log -iq + tcfFin; } + + tcfChk "test, MAIL test" && { + create_config '' MAIL: + last_line_num=`cat /var/log/maillog | wc -l` + rlRun "su -c 'sudo /bin/ls /' - $testUser" 0 + get_last_mail_log + rlAssertGrep 'emailto@domain.com' last_mail.log -iq + rlRun "su -c 'sudo /bin/ls /' - ${testUser[1]}" 0 + get_last_mail_log + rlAssertNotGrep 'emailto@domain.com' last_mail.log -iq + tcfFin; } + + tcfFin; } + + tcfChk "cleanup" && { + CleanupDo --mark + tcfFin; } + tcfFin; } + rlPhaseEnd; } + + rlPhaseStartTest "test mute unknown defaults" && { + CleanupRegister --mark 'rlRun "rlFileRestore --namespace mute_unknown"' + rlRun "rlFileBackup --clean --namespace mute_unknown /etc/sudoers.d/test" + cat > /etc/sudoers.d/test < /etc/sudoers.d/test < +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2013 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/CoreOS/sudo/Sanity/upstream-testsuite-execution-and-rebuild-test +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) runtest.sh Makefile PURPOSE + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Ales Marecek " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: This test rebuild sudo source rpm and checks that rebuild is OK. The second - main - part is about upstream testsuite execution." >> $(METADATA) + @echo "Type: Sanity" >> $(METADATA) + @echo "TestTime: 15m" >> $(METADATA) + @echo "RunFor: sudo" >> $(METADATA) + @echo "Requires: sudo" >> $(METADATA) + @echo "Requires: sed" >> $(METADATA) + @echo "Requires: grep" >> $(METADATA) + @echo "Requires: rpm-build" >> $(METADATA) + @echo "Requires: yum-utils" >> $(METADATA) + @echo "Requires: make" >> $(METADATA) + @echo "Requires: libcap-devel" >> $(METADATA) + @echo "Requires: audit-libs-devel" >> $(METADATA) + @echo "Priority: Normal" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + @echo "Confidential: no" >> $(METADATA) + @echo "Destructive: no" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/upstream-testsuite-execution-and-rebuild-test/PURPOSE b/tests/upstream-testsuite-execution-and-rebuild-test/PURPOSE new file mode 100644 index 0000000..26ca2b6 --- /dev/null +++ b/tests/upstream-testsuite-execution-and-rebuild-test/PURPOSE @@ -0,0 +1,3 @@ +PURPOSE of /CoreOS/sudo/Sanity/upstream-testsuite-execution-and-rebuild-test +Description: This test rebuild sudo source rpm and checks that rebuild is OK. The second - main - part is about upstream testsuite execution. +Author: Ales Marecek diff --git a/tests/upstream-testsuite-execution-and-rebuild-test/runtest.sh b/tests/upstream-testsuite-execution-and-rebuild-test/runtest.sh new file mode 100755 index 0000000..8748a8c --- /dev/null +++ b/tests/upstream-testsuite-execution-and-rebuild-test/runtest.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# vim: dict=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# runtest.sh of /CoreOS/sudo/Sanity/upstream-testsuite-execution-and-rebuild-test +# Description: This test rebuild sudo source rpm and checks that rebuild is OK. The second - main - part is about upstream testsuite execution. +# Author: Ales Marecek +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2013 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include Beaker environment +. /usr/bin/rhts-environment.sh || exit 1 +. /usr/share/beakerlib/beakerlib.sh || exit 1 + +PACKAGE="sudo" +_SPEC_DIR="$(rpm --eval=%_specdir)" +_BUILD_DIR="$(rpm --eval=%_builddir)" +_LOG_REBUILD_F="${PACKAGE}-rebuild.log" +_LOG_TESTSUITE_F="${PACKAGE}-testsuite.log" + + +rlJournalStart + rlPhaseStartSetup + rlAssertRpm $PACKAGE + rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory" + rlRun "pushd $TmpDir" + # Source package is needed for code inspection + rlFetchSrcForInstalled "${PACKAGE}" || yumdownloader --source "${PACKAGE}" + rlRun "find . -size 0 -delete" 0 "Remove empty src.rpm-s" + rlRun "yum-builddep -y --nogpgcheck ${PACKAGE}-*.src.rpm" 0 "Installing build dependencies" + [ -d ${_BUILD_DIR} ] && rlRun "rm -rf ${_BUILD_DIR}/*" 0 "Cleaning build directory" + rlRun "rpm -ivh ${PACKAGE}-*.src.rpm" 0 "Installing source rpm" + rlPhaseEnd + + rlPhaseStartTest + rlRun "QA_RPATHS=0x0002 rpmbuild -ba ${_SPEC_DIR}/${PACKAGE}.spec" 0 "Test: Rebuild of source '${PACKAGE}' package" + rlGetPhaseState + if [ $? -eq 0 ]; then + cd ${_BUILD_DIR}/${PACKAGE}-* + rlRun -s "make check" 0 "Test: Upstream testsuite" + cd ${TmpDir} + while read -r I; do + if [[ "$I" =~ $(echo '([^:]+): .+ tests run, .+ errors, (.*)% success rate') ]]; then + [[ "${BASH_REMATCH[2]}" == "100" ]] + rlAssert0 "Test: Checking tests of '${BASH_REMATCH[1]}'" $? + elif [[ "$I" =~ $(echo "([^:]+): .+ tests passed; (.+)/.+ tests failed") ]]; then + [[ "${BASH_REMATCH[2]}" == "0" ]] + rlAssert0 "Test: Checking tests of '${BASH_REMATCH[1]}'" $? + fi + done < $rlRun_LOG + rm -f $rlRun_LOG + else + rlFail "Skipping testsuite part because rebuild part failed." + fi + rlPhaseEnd + + rlPhaseStartCleanup + rlRun "popd" + rlRun "rm -r $TmpDir" 0 "Removing tmp directory" + rlPhaseEnd +rlJournalPrintText +rlJournalEnd diff --git a/tests/use_pty-option/Makefile b/tests/use_pty-option/Makefile new file mode 100644 index 0000000..e0cb676 --- /dev/null +++ b/tests/use_pty-option/Makefile @@ -0,0 +1,72 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /CoreOS/sudo/Sanity/use_pty-option +# Description: checks if use_pty option in /etc/sudoers works as expected +# Author: Milos Malik +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2011 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/CoreOS/sudo/Sanity/use_pty-option +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) runtest.sh Makefile PURPOSE forker.sh ssh-sudo.exp + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + chmod a+x runtest.sh + chmod a+x ssh-sudo.exp + +clean: + rm -f *~ $(BUILT_FILES) + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Milos Malik " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: checks if use_pty option in /etc/sudoers works as expected" >> $(METADATA) + @echo "Type: Sanity" >> $(METADATA) + @echo "TestTime: 10m" >> $(METADATA) + @echo "RunFor: sudo" >> $(METADATA) + @echo "Requires: sudo" >> $(METADATA) + @echo "Requires: iputils" >> $(METADATA) + @echo "Requires: sed" >> $(METADATA) + @echo "Requires: grep" >> $(METADATA) + @echo "Requires: mktemp" >> $(METADATA) + @echo "Requires: openssh-server" >> $(METADATA) + @echo "Requires: openssh-clients" >> $(METADATA) + @echo "Requires: expect" >> $(METADATA) + @echo "Requires: shadow-utils" >> $(METADATA) + @echo "Priority: Normal" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + @echo "Confidential: no" >> $(METADATA) + @echo "Destructive: no" >> $(METADATA) + + rhts-lint $(METADATA) + diff --git a/tests/use_pty-option/PURPOSE b/tests/use_pty-option/PURPOSE new file mode 100644 index 0000000..ecc2748 --- /dev/null +++ b/tests/use_pty-option/PURPOSE @@ -0,0 +1,4 @@ +PURPOSE of /CoreOS/sudo/Sanity/use_pty-option +Description: checks if use_pty option in /etc/sudoers works as expected +Author: Milos Malik + diff --git a/tests/use_pty-option/forker.sh b/tests/use_pty-option/forker.sh new file mode 100644 index 0000000..0eecf07 --- /dev/null +++ b/tests/use_pty-option/forker.sh @@ -0,0 +1,5 @@ +#!/bin/bash +for i in `seq 1 10`; do + ( ping -c 10 -q www.redhat.com & ) +done + diff --git a/tests/use_pty-option/runtest.sh b/tests/use_pty-option/runtest.sh new file mode 100755 index 0000000..054d752 --- /dev/null +++ b/tests/use_pty-option/runtest.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# vim: dict=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# runtest.sh of /CoreOS/sudo/Sanity/use_pty-option +# Description: checks if use_pty option in /etc/sudoers works as expected +# Author: Milos Malik +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2011 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include rhts environment +. /usr/bin/rhts-environment.sh +. /usr/share/beakerlib/beakerlib.sh + +PACKAGE="sudo" +USER_NAME="user${RANDOM}" +USER_SECRET="s3kr3T${RANDOM}" + +rlJournalStart + rlPhaseStartSetup + rlAssertRpm ${PACKAGE} + OUTPUT_FILE=`mktemp` + rlFileBackup /etc/sudoers + rlFileBackup --clean ~/.ssh + + rlRun "useradd ${USER_NAME}" + rlRun "echo ${USER_SECRET} | passwd --stdin ${USER_NAME}" + rlRun "cp ./forker.sh /home/${USER_NAME}/" + rlRun "chown ${USER_NAME}:${USER_NAME} /home/${USER_NAME}/forker.sh" + rlRun "chmod u+x /home/${USER_NAME}/forker.sh" + rlRun "echo \"${USER_NAME} ALL = NOPASSWD: /home/${USER_NAME}/forker.sh\" >> /etc/sudoers" + rlRun "sed -i 's/^.*requiretty.*$//' /etc/sudoers" + rlRun "echo \"Defaults !requiretty\" >> /etc/sudoers" + rlRun "> ~/.ssh/known_hosts" + rlPhaseEnd + + rlPhaseStartTest "use_pty option is enabled" + rlRun "sed -i 's/^.*use_pty.*$//' /etc/sudoers" + rlRun "echo \"Defaults use_pty\" >> /etc/sudoers" + rlRun "./ssh-sudo.exp ${USER_NAME} ${USER_SECRET} localhost ./forker.sh 2>&1 | tee ${OUTPUT_FILE}" + rlAssertNotGrep "ping statistics" ${OUTPUT_FILE} + rlPhaseEnd + + rlPhaseStartTest "use_pty option is disabled" + rlRun "sed -i 's/^.*use_pty.*$//' /etc/sudoers" + rlRun "echo \"Defaults !use_pty\" >> /etc/sudoers" + rlRun "./ssh-sudo.exp ${USER_NAME} ${USER_SECRET} localhost ./forker.sh 2>&1 | tee ${OUTPUT_FILE}" + rlAssertGrep "ping statistics" ${OUTPUT_FILE} + rlPhaseEnd + + rlPhaseStartCleanup + rlRun "userdel -rf ${USER_NAME}" + rlFileRestore + rm -f ${OUTPUT_FILE} + rlPhaseEnd +rlJournalPrintText +rlJournalEnd + diff --git a/tests/use_pty-option/ssh-sudo.exp b/tests/use_pty-option/ssh-sudo.exp new file mode 100755 index 0000000..afbac4c --- /dev/null +++ b/tests/use_pty-option/ssh-sudo.exp @@ -0,0 +1,20 @@ +#!/usr/bin/expect -f +# usage: +# ./ssh-sudo.exp username password hostname command +set username [lrange $argv 0 0] +set password [lrange $argv 1 1] +set hostname [lrange $argv 2 2] +set command [lrange $argv 3 3] +set timeout 15 +spawn ssh $username@$hostname sudo $command +expect "*yes/no*" { + send -- "yes\r" +} +expect "*assword*" { + send -- "$password\r" +} +expect "*assword*" { + send -- "$password\r" +} +expect eof +