Compare commits

..

30 Commits

Author SHA1 Message Date
0a903feb12 Merge branch 'master' into more_time
Some checks are pending
Check for merge conflicts / main (push) Waiting to run
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (alpine_3_21) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_23) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_13) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_43) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Check for merge conflicts / main (pull_request_target) Waiting to run
2026-03-18 14:08:30 +00:00
15874b002e Merge pull request 'fix/version_file' (#7) from fix/version_file into master
Some checks failed
CodeQL / Analyze (push) Has been cancelled
Check for merge conflicts / main (push) Has been cancelled
Sync Back to Development / Syncing branches (push) Has been cancelled
Reviewed-on: #7
2026-03-18 14:06:44 +00:00
ca9de23ca5 Merge branch 'master' into fix/version_file
Some checks are pending
Check for merge conflicts / main (push) Waiting to run
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (alpine_3_21) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_23) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_13) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_43) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Check for merge conflicts / main (pull_request_target) Waiting to run
2026-03-18 14:06:35 +00:00
d807c40ba5 Merge pull request 'Install ARMv7 binary even when we detect a 64bit (aarch64) CPU but the operating system is 32bit. See FTL#2494 for reference' (#5) from tweak/32bitARM into master
Some checks failed
CodeQL / Analyze (push) Has been cancelled
Check for merge conflicts / main (push) Has been cancelled
Sync Back to Development / Syncing branches (push) Has been cancelled
Reviewed-on: #5
2026-03-18 14:05:21 +00:00
6ee7eca1e5 Merge branch 'master' into tweak/32bitARM
Some checks are pending
Check for merge conflicts / main (push) Waiting to run
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (alpine_3_21) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_23) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_13) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_43) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Check for merge conflicts / main (pull_request_target) Waiting to run
2026-03-18 14:05:15 +00:00
396f85614d Merge pull request 'Fix permission for *.etag files after gravity run' (#4) from fix/etag into master
Some checks failed
CodeQL / Analyze (push) Has been cancelled
Check for merge conflicts / main (push) Has been cancelled
Sync Back to Development / Syncing branches (push) Has been cancelled
Reviewed-on: #4
2026-03-18 14:04:29 +00:00
c95094a6d3 Merge branch 'master' into fix/etag
Some checks are pending
Check for merge conflicts / main (push) Waiting to run
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (alpine_3_21) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_23) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_13) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_43) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Check for merge conflicts / main (pull_request_target) Waiting to run
2026-03-18 14:04:22 +00:00
0159461cc0 Merge pull request 'fix/gravity_permission_check' (#3) from fix/gravity_permission_check into master
Some checks failed
CodeQL / Analyze (push) Has been cancelled
Check for merge conflicts / main (push) Has been cancelled
Sync Back to Development / Syncing branches (push) Has been cancelled
Reviewed-on: #3
2026-03-18 14:03:54 +00:00
8d24316758 Merge branch 'master' into fix/gravity_permission_check
Some checks are pending
Check for merge conflicts / main (push) Waiting to run
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (alpine_3_21) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_23) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_13) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_43) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Check for merge conflicts / main (pull_request_target) Waiting to run
2026-03-18 14:03:46 +00:00
e972595170 Merge pull request 'unsupported/binary' (#2) from unsupported/binary into master
Some checks failed
CodeQL / Analyze (push) Has been cancelled
Check for merge conflicts / main (push) Has been cancelled
Sync Back to Development / Syncing branches (push) Has been cancelled
Reviewed-on: #2
2026-03-18 14:03:20 +00:00
ba86a1c23f Merge branch 'master' into unsupported/binary
Some checks are pending
Check for merge conflicts / main (push) Waiting to run
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (alpine_3_21) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_23) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_13) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_43) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Check for merge conflicts / main (pull_request_target) Waiting to run
2026-03-18 14:03:11 +00:00
1703f169ba Merge pull request 'Move unattended check to the top of the script - exit early if /etc/pihole/pihole.toml file is not found,' (#1) from tweak/6380 into master
Some checks failed
CodeQL / Analyze (push) Has been cancelled
Check for merge conflicts / main (push) Has been cancelled
Sync Back to Development / Syncing branches (push) Has been cancelled
Reviewed-on: #1
2026-03-18 14:02:47 +00:00
fbb3798dc2 Merge branch 'master' into tweak/6380
Some checks are pending
Check for merge conflicts / main (push) Waiting to run
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (alpine_3_21) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_23) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_13) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_43) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Check for merge conflicts / main (pull_request_target) Waiting to run
2026-03-18 14:02:37 +00:00
Christian König
4125bcccdc Files should be created before calling addOrEditKeyValPair
Some checks are pending
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (alpine_3_21) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_23) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_13) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_43) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Signed-off-by: Christian König <github@yubiuser.dev>
2026-02-18 09:25:10 +01:00
Christian König
ac37014628 Truncate version file instead of removing and creating freshly
Signed-off-by: Christian König <github@yubiuser.dev>
2026-02-18 09:22:11 +01:00
Adam Warner
a393dd83f3 v6.4 (#6536) 2026-02-17 20:26:56 +00:00
Christian König
d765ce768f Wipe version file before creating a new one
Signed-off-by: yubiuser <github@yubiuser.dev>
2026-02-16 20:11:17 +01:00
yubiuser
527895a377 Fix indentation
Some checks are pending
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (alpine_3_21) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (alpine_3_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_13) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Co-authored-by: RD WebDesign <github@rdwebdesign.com.br>
Signed-off-by: yubiuser <github@yubiuser.dev>
2025-10-24 21:07:12 +02:00
Christian König
11344c39f5 Prevent URLs like file:/./ to circumvent permission check
Signed-off-by: Christian König <github@yubiuser.dev>
2025-10-23 22:22:02 +02:00
Christian König
b2e56662c0 Loose requirements for local file access for gravity
Signed-off-by: yubiuser <github@yubiuser.dev>
2025-10-23 22:21:36 +02:00
Adam Warner
5ed52554d7 Move unattended check to the top of the script - exit early if /etc/pihole/pihole.toml file is not found,
Some checks are pending
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-08-11 14:55:39 +01:00
Christian König
a9e3d3b728 Use --skipFTL flag also for pihole repair and checkout
Some checks are pending
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Signed-off-by: Christian König <github@yubiuser.dev>
2025-07-21 12:07:33 +02:00
Christian König
a8db4def9a Use flag --skipFTL instead of env var PIHOLE_SKIP_FTL_CHECK
Signed-off-by: Christian König <github@yubiuser.dev>
2025-07-21 11:54:12 +02:00
Christian König
95021fce58 Fix permission for *.etag files after gravity run
Some checks are pending
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Signed-off-by: Christian König <github@yubiuser.dev>
2025-07-16 21:00:05 +02:00
Christian König
463086ef23 Skip FTL update check if $PIHOLE_SKIP_FTL_CHECK is set to true
Signed-off-by: Christian König <github@yubiuser.dev>
2025-07-10 21:57:38 +02:00
Christian König
f3e04117f6 Let users know we skipped the FTL checks
Co-authored-by: davygravy <davygravy@users.noreply.github.com>
Signed-off-by: Christian König <github@yubiuser.dev>
2025-07-10 21:56:52 +02:00
Christian König
f67a8e5110 Only set PIHOLE_SKIP_FTL_CHECK if not already set by env variable
Signed-off-by: Christian König <github@yubiuser.dev>
2025-07-10 21:56:52 +02:00
Christian König
3f7f6f0294 Allow uses to skip binary check and installing FTL in case the use a self-compiled binary
Signed-off-by: Christian König <github@yubiuser.dev>
2025-07-10 21:56:52 +02:00
DL6ER
082d74eeb1 Install ARMv7 binary even when we detect a 64bit (aarch64) CPU but the operating system is 32bit. See FTL#2494 for reference
Some checks are pending
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-06-06 06:44:17 +02:00
Christian König
1a3a23a867 Give FTL 120 seconds to shutdown
Some checks are pending
CodeQL / Analyze (pull_request) Waiting to run
Test Supported Distributions / smoke-tests (pull_request) Waiting to run
Test Supported Distributions / distro-test (centos_10) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (centos_9) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_11) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (debian_12) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_40) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_41) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (fedora_42) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_20) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_22) (pull_request) Blocked by required conditions
Test Supported Distributions / distro-test (ubuntu_24) (pull_request) Blocked by required conditions
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-26 21:38:26 +02:00
45 changed files with 1140 additions and 831 deletions

View File

@@ -29,12 +29,12 @@ jobs:
# Initializes the CodeQL tools for scanning.
-
name: Initialize CodeQL
uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 #v4.32.6
uses: github/codeql-action/init@9e907b5e64f6b83e7804b09294d44122997950d6 #v4.32.3
with:
languages: 'python'
-
name: Autobuild
uses: github/codeql-action/autobuild@0d579ffd059c29b07949a3cce3983f0780820c98 #v4.32.6
uses: github/codeql-action/autobuild@9e907b5e64f6b83e7804b09294d44122997950d6 #v4.32.3
-
name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 #v4.32.6
uses: github/codeql-action/analyze@9e907b5e64f6b83e7804b09294d44122997950d6 #v4.32.3

View File

@@ -17,7 +17,7 @@ jobs:
issues: write
steps:
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f #v10.2.0
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d #v10.1.1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 30

View File

@@ -17,7 +17,7 @@ jobs:
pull-requests: write
steps:
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f #v10.2.0
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d #v10.1.1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
# Do not automatically mark PR/issue as stale

View File

@@ -7,6 +7,11 @@ on:
permissions:
contents: read
env:
FORCE_COLOR: 1
PYTHONUNBUFFERED: 1
PYTHONUTF8: 1
jobs:
smoke-tests:
if: github.event.pull_request.draft == false
@@ -20,18 +25,18 @@ jobs:
- name: Check scripts in repository are executable
run: |
IFS=$'\n';
for f in $(find . -name '*.sh' -o -name '*.bats'); do if [[ ! -x $f ]]; then echo "$f is not executable" && FAIL=1; fi ;done
for f in $(find . -name '*.sh'); do if [[ ! -x $f ]]; then echo "$f is not executable" && FAIL=1; fi ;done
unset IFS;
# If FAIL is 1 then we fail.
[[ $FAIL == 1 ]] && exit 1 || echo "Scripts are executable!"
- name: Differential ShellCheck
if: github.event_name == 'pull_request'
uses: redhat-plumbers-in-action/differential-shellcheck@d965e66ec0b3b2f821f75c8eff9b12442d9a7d1e #v5.5.6
with:
severity: warning
display-engine: sarif-fmt
- name: Spell-Checking
uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 #v2.2
with:
@@ -43,6 +48,12 @@ jobs:
- name: Run editorconfig-checker
run: editorconfig-checker
- name: Check python code formatting with black
uses: psf/black@6305bf1ae645ab7541be4f5028a86239316178eb #26.1.0
with:
src: "./test"
options: "--check --diff --color"
distro-test:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
@@ -68,9 +79,22 @@ jobs:
alpine_3_22,
alpine_3_23,
]
env:
DISTRO: ${{matrix.distro}}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
- name: Run BATS test suite for ${{ matrix.distro }}
run: DISTRO=${{ matrix.distro }} bash test/run.sh
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 #v6.2.0
with:
python-version: "3.13"
- name: Install wheel
run: pip install wheel
- name: Install dependencies
run: pip install -r test/requirements.txt
- name: Test with tox
run: tox -c test/tox.${DISTRO}.ini

10
.gitignore vendored
View File

@@ -1,7 +1,15 @@
.DS_Store
*.pyc
*.swp
__pycache__
.cache
.pytest_cache
.tox
.eggs
*.egg-info
.idea/
*.iml
.vscode/
.venv/
.fleet/
test/libs/
.cache/

View File

@@ -41,6 +41,22 @@ warning1() {
}
checkout() {
local skipFTL additionalFlag
skipFTL=false
# Check arguments
for var in "$@"; do
case "$var" in
"--skipFTL") skipFTL=true ;;
esac
done
if [ "${skipFTL}" == true ]; then
additionalFlag="--skipFTL"
else
additionalFlag=""
fi
local corebranches
local webbranches
@@ -235,7 +251,7 @@ checkout() {
# Force updating everything
if [[ ! "${1}" == "web" && ! "${1}" == "ftl" ]]; then
echo -e " ${INFO} Running installer to upgrade your installation"
if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then
if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended ${additionalFlag}; then
exit 0
else
echo -e " ${COL_RED} Error: Unable to complete update, please contact support${COL_NC}"

View File

@@ -169,7 +169,7 @@ initialize_debug() {
# Display that the debug process is beginning
log_write "${COL_PURPLE}*** [ INITIALIZING ]${COL_NC}"
# Timestamp the start of the log
log_write "${INFO} $(date "+%Y-%m-%d %H:%M:%S") debug log has been initialized."
log_write "${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initialized."
# Uptime of the system
# credits to https://stackoverflow.com/questions/28353409/bash-format-uptime-to-show-days-hours-minutes
system_uptime=$(uptime | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/){if ($9=="min") {d=$6;m=$8} else {d=$6;h=$8;m=$9}} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes"}')

View File

@@ -15,7 +15,7 @@ if [[ -f ${coltable} ]]; then
source ${coltable}
fi
PI_HOLE_SCRIPT_DIR="/opt/pihole"
readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck source=./advanced/Scripts/utils.sh
source "${utilsfile}"

View File

@@ -149,31 +149,37 @@ main() {
echo -e " ${INFO} Web Interface:\\t${COL_GREEN}up to date${COL_NC}"
fi
local funcOutput
funcOutput=$(get_binary_name) #Store output of get_binary_name here
local binary
binary="pihole-FTL${funcOutput##*pihole-FTL}" #binary name will be the last line of the output of get_binary_name (it always begins with pihole-FTL)
# Allow the user to skip this check if they are using a self-compiled FTL binary from an unsupported architecture
if [ "${skipFTL}" != true ]; then
local funcOutput
funcOutput=$(get_binary_name) #Store output of get_binary_name here
local binary
binary="pihole-FTL${funcOutput##*pihole-FTL}" #binary name will be the last line of the output of get_binary_name (it always begins with pihole-FTL)
if FTLcheckUpdate "${binary}" &>/dev/null; then
FTL_update=true
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
if FTLcheckUpdate "${binary}" &>/dev/null; then
FTL_update=true
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
else
case $? in
1)
echo -e " ${INFO} FTL:\\t\\t${COL_GREEN}up to date${COL_NC}"
;;
2)
echo -e " ${INFO} FTL:\\t\\t${COL_RED}Branch is not available.${COL_NC}\\n\\t\\t\\tUse ${COL_GREEN}pihole checkout ftl [branchname]${COL_NC} to switch to a valid branch."
exit 1
;;
3)
echo -e " ${INFO} FTL:\\t\\t${COL_RED}Something has gone wrong, cannot reach download server${COL_NC}"
exit 1
;;
*)
echo -e " ${INFO} FTL:\\t\\t${COL_RED}Something has gone wrong, contact support${COL_NC}"
exit 1
esac
FTL_update=false
fi
else
case $? in
1)
echo -e " ${INFO} FTL:\\t\\t${COL_GREEN}up to date${COL_NC}"
;;
2)
echo -e " ${INFO} FTL:\\t\\t${COL_RED}Branch is not available.${COL_NC}\\n\\t\\t\\tUse ${COL_GREEN}pihole checkout ftl [branchname]${COL_NC} to switch to a valid branch."
exit 1
;;
3)
echo -e " ${INFO} FTL:\\t\\t${COL_RED}Something has gone wrong, cannot reach download server${COL_NC}"
exit 1
;;
*)
echo -e " ${INFO} FTL:\\t\\t${COL_RED}Something has gone wrong, contact support${COL_NC}"
exit 1
esac
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}--skipFTL set - update check skipped${COL_NC}"
FTL_update=false
fi
@@ -222,7 +228,14 @@ main() {
fi
if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --repair --unattended || \
local addionalFlag
if [[ ${skipFTL} == true ]]; then
addionalFlag="--skipFTL"
else
addionalFlag=""
fi
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --repair --unattended ${addionalFlag} || \
echo -e "${basicError}" && exit 1
fi
@@ -242,8 +255,15 @@ main() {
exit 0
}
if [[ "$1" == "--check-only" ]]; then
CHECK_ONLY=true
fi
CHECK_ONLY=false
skipFTL=false
# Check arguments
for var in "$@"; do
case "$var" in
"--check-only") CHECK_ONLY=true ;;
"--skipFTL") skipFTL=true ;;
esac
done
main

View File

@@ -50,9 +50,10 @@ rm -f "/etc/pihole/GitHubVersions"
rm -f "/etc/pihole/localbranches"
rm -f "/etc/pihole/localversions"
# Create new versions file if it does not exist
VERSION_FILE="/etc/pihole/versions"
touch "${VERSION_FILE}"
# Truncates the file to zero length if it exists to clear it up, otherwise creates an empty file.
truncate -s 0 "${VERSION_FILE}"
chmod 644 "${VERSION_FILE}"
# if /pihole.docker.tag file exists, we will use it's value later in this script

View File

@@ -30,9 +30,6 @@ addOrEditKeyValPair() {
local key="${2}"
local value="${3}"
# touch file to prevent grep error if file does not exist yet
touch "${file}"
if grep -q "^${key}=" "${file}"; then
# Key already exists in file, modify the value
sed -i "/^${key}=/c\\${key}=${value}" "${file}"

View File

@@ -57,9 +57,9 @@ start() {
stop() {
if is_running; then
kill "${FTL_PID}"
# Give FTL 60 seconds to gracefully stop
# Give FTL 120 seconds to gracefully stop
i=1
while [ "${i}" -le 60 ]; do
while [ "${i}" -le 120 ]; do
if ! is_running; then
break
fi

View File

@@ -28,7 +28,7 @@ ExecReload=/bin/kill -HUP $MAINPID
ExecStopPost=+/opt/pihole/pihole-FTL-poststop.sh
# Use graceful shutdown with a reasonable timeout
TimeoutStopSec=60s
TimeoutStopSec=120s
# Make /usr, /boot, /etc and possibly some more folders read-only...
ProtectSystem=full

View File

@@ -188,14 +188,27 @@ PIHOLE_META_DEPS_APK=(
# The runUnattended flag is one example of this
repair=false
runUnattended=false
skipFTL=false
# Check arguments for the undocumented flags
for var in "$@"; do
case "${var}" in
"--repair") repair=true ;;
"--unattended") runUnattended=true ;;
"--skipFTL") skipFTL=true ;;
esac
done
if [[ "${runUnattended}" == true ]]; then
# In order to run an unattended setup, a pre-seeded /etc/pihole/pihole.toml must exist
if [[ ! -f "${PI_HOLE_CONFIG_DIR}/pihole.toml" ]]; then
printf " %b Error: \"%s\" not found. Cannot run unattended setup\\n" "${CROSS}" "${PI_HOLE_CONFIG_DIR}/pihole.toml"
exit 1
fi
printf " %b Performing unattended setup, no dialogs will be displayed\\n" "${INFO}"
# also disable debconf-apt-progress dialogs
export DEBIAN_FRONTEND="noninteractive"
fi
# If the color table file exists,
if [[ -f "${coltable}" ]]; then
# source it
@@ -1950,9 +1963,18 @@ get_binary_name() {
# If the machine is aarch64 (armv8)
if [[ "${machine}" == "aarch64" ]]; then
# If AArch64 is found (e.g., BCM2711 in Raspberry Pi 4)
printf "%b %b Detected AArch64 (64 Bit ARM) architecture\\n" "${OVER}" "${TICK}"
l_binary="pihole-FTL-arm64"
if [[ "$(getconf LONG_BIT)" == "64" ]]; then
# If the OS is 64 bit, we use the arm64 binary
printf "%b %b Detected AArch64 (64 Bit ARM) architecture\\n" "${OVER}" "${TICK}"
l_binary="pihole-FTL-arm64"
else
# If the OS is 32 bit, we use the armv7 binary (aarch64 is actually armv8)
# Even though the machine is 64 bit capable, this makes debugging
# very hard as 32bit tools like gdb, etc. cannot analyze the 64 bit
# binary. See FTL issue #2494 for such an example.
printf "%b %b Detected AArch64 (64 Bit ARM) architecture with 32 bit OS\\n" "${OVER}" "${TICK}"
l_binary="pihole-FTL-armv7"
fi
elif [[ "${machine}" == "arm"* ]]; then
# ARM 32 bit
# Get supported processor from other binaries installed on the system
@@ -2322,21 +2344,18 @@ main() {
# Check if there is a usable FTL binary available on this architecture - do
# this early on as FTL is a hard dependency for Pi-hole
local funcOutput
funcOutput=$(get_binary_name) #Store output of get_binary_name here
# Abort early if this processor is not supported (get_binary_name returns empty string)
if [[ "${funcOutput}" == "" ]]; then
printf " %b Upgrade/install aborted\\n" "${CROSS}" "${DISTRO_NAME}"
exit 1
fi
if [[ "${fresh_install}" == false ]]; then
# if it's running unattended,
if [[ "${runUnattended}" == true ]]; then
printf " %b Performing unattended setup, no dialogs will be displayed\\n" "${INFO}"
# also disable debconf-apt-progress dialogs
export DEBIAN_FRONTEND="noninteractive"
# Allow the user to skip this check if they are using a self-compiled FTL binary from an unsupported architecture
if [ "${skipFTL}" != true ]; then
# Get the binary name for the current architecture
local funcOutput
funcOutput=$(get_binary_name) #Store output of get_binary_name here
# Abort early if this processor is not supported (get_binary_name returns empty string)
if [[ "${funcOutput}" == "" ]]; then
printf " %b Upgrade/install aborted\\n" "${CROSS}" "${DISTRO_NAME}"
exit 1
fi
else
printf " %b %b--skipFTL set - skipping architecture check%b\\n" "${INFO}" "${COL_YELLOW}" "${COL_NC}"
fi
if [[ "${fresh_install}" == true ]]; then
@@ -2369,13 +2388,18 @@ main() {
create_pihole_user
# Download and install FTL
local binary
binary="pihole-FTL${funcOutput##*pihole-FTL}" #binary name will be the last line of the output of get_binary_name (it always begins with pihole-FTL)
local theRest
theRest="${funcOutput%pihole-FTL*}" # Print the rest of get_binary_name's output to display (cut out from first instance of "pihole-FTL")
if ! FTLdetect "${binary}" "${theRest}"; then
printf " %b FTL Engine not installed\\n" "${CROSS}"
exit 1
# Allow the user to skip this check if they are using a self-compiled FTL binary from an unsupported architecture
if [ "${skipFTL}" != true ]; then
local binary
binary="pihole-FTL${funcOutput##*pihole-FTL}" #binary name will be the last line of the output of get_binary_name (it always begins with pihole-FTL)
local theRest
theRest="${funcOutput%pihole-FTL*}" # Print the rest of get_binary_name's output to display (cut out from first instance of "pihole-FTL")
if ! FTLdetect "${binary}" "${theRest}"; then
printf " %b FTL Engine not installed\\n" "${CROSS}"
exit 1
fi
else
printf " %b %b--skipFTL set - skipping FTL binary installation%b\\n" "${INFO}" "${COL_YELLOW}" "${COL_NC}"
fi
# Install and log everything to a file

View File

@@ -612,7 +612,7 @@ compareLists() {
gravity_DownloadBlocklistFromUrl() {
local url="${1}" adlistID="${2}" saveLocation="${3}" compression="${4}" gravity_type="${5}" domain="${6}"
local listCurlBuffer str httpCode success="" ip customUpstreamResolver=""
local file_path permissions ip_addr port blocked=false download=true
local file_path ip_addr port blocked=false download=true
# modifiedOptions is an array to store all the options used to check if the adlist has been changed upstream
local modifiedOptions=()
@@ -721,29 +721,40 @@ gravity_DownloadBlocklistFromUrl() {
fi
fi
# If we are going to "download" a local file, we first check if the target
# file has a+r permission. We explicitly check for all+read because we want
# to make sure that the file is readable by everyone and not just the user
# running the script.
if [[ $url == "file://"* ]]; then
# If we "download" a local file (file://), verify read access before using it.
# When running as root (e.g., via pihole -g), check that the 'pihole' user can read the file
# to match the effective runtime user of FTL; otherwise, check the current user's read access
# (e.g., in Docker or when invoked by a non-root user). The target must
# resolve to a regular file and be readable by the evaluated user.
if [[ "${url}" == "file:/"* ]]; then
# Get the file path
file_path=$(echo "$url" | cut -d'/' -f3-)
file_path=$(echo "${url}" | cut -d'/' -f3-)
# Check if the file exists and is a regular file (i.e. not a socket, fifo, tty, block). Might still be a symlink.
if [[ ! -f $file_path ]]; then
# Output that the file does not exist
echo -e "${OVER} ${CROSS} ${file_path} does not exist"
download=false
else
# Check if the file or a file referenced by the symlink has a+r permissions
permissions=$(stat -L -c "%a" "$file_path")
if [[ $permissions == *4 || $permissions == *5 || $permissions == *6 || $permissions == *7 ]]; then
# Output that we are using the local file
echo -e "${OVER} ${INFO} Using local file ${file_path}"
else
# Output that the file does not have the correct permissions
echo -e "${OVER} ${CROSS} Cannot read file (file needs to have a+r permission)"
if [[ ! -f ${file_path} ]]; then
# Output that the file does not exist
echo -e "${OVER} ${CROSS} ${file_path} does not exist"
download=false
fi
else
if [ "$(id -un)" == "root" ]; then
# If we are root, we need to check if the pihole user has read permission
# otherwise, we might read files that the pihole user should not be able to read
if sudo -u pihole test -r "${file_path}"; then
echo -e "${OVER} ${INFO} Using local file ${file_path}"
else
echo -e "${OVER} ${CROSS} Cannot read file (user 'pihole' lacks read permission)"
download=false
fi
else
# If we are not root, we just check if the current user has read permission
if [[ -r "${file_path}" ]]; then
# Output that we are using the local file
echo -e "${OVER} ${INFO} Using local file ${file_path}"
else
# Output that the file is not readable by the current user
echo -e "${OVER} ${CROSS} Cannot read file (current user '$(id -un)' lacks read permission)"
download=false
fi
fi
fi
fi
@@ -811,6 +822,10 @@ gravity_DownloadBlocklistFromUrl() {
fix_owner_permissions "${saveLocation}"
# Compare lists if they are identical
compareLists "${adlistID}" "${saveLocation}"
# Set permissions for the *.etag file
if [[ -f "${saveLocation}.etag" ]]; then
fix_owner_permissions "${saveLocation}.etag"
fi
# Add domains to database table file
pihole-FTL "${gravity_type}" parseList "${saveLocation}" "${gravityTEMPfile}" "${adlistID}"
done="true"

19
pihole
View File

@@ -125,7 +125,22 @@ repairPiholeFunc() {
if [ -n "${DOCKER_VERSION}" ]; then
unsupportedFunc
else
/etc/.pihole/automated\ install/basic-install.sh --repair
local skipFTL additionalFlag
skipFTL=false
# Check arguments
for var in "$@"; do
case "$var" in
"--skipFTL") skipFTL=true ;;
esac
done
if [ "${skipFTL}" == true ]; then
additionalFlag="--skipFTL"
else
additionalFlag=""
fi
/etc/.pihole/automated\ install/basic-install.sh --repair ${additionalFlag}
exit 0;
fi
}
@@ -601,7 +616,7 @@ case "${1}" in
"-d" | "debug" ) debugFunc "$@";;
"-f" | "flush" ) flushFunc "$@";;
"-up" | "updatePihole" ) updatePiholeFunc "$@";;
"-r" | "repair" ) repairPiholeFunc;;
"-r" | "repair" ) repairPiholeFunc "$@";;
"-g" | "updateGravity" ) updateGravityFunc "$@";;
"-l" | "logging" ) piholeLogging "$@";;
"uninstall" ) uninstallFunc;;

0
test/__init__.py Normal file
View File

175
test/conftest.py Normal file
View File

@@ -0,0 +1,175 @@
import pytest
import testinfra
import testinfra.backend.docker
import subprocess
from textwrap import dedent
IMAGE = "pytest_pihole:test_container"
tick_box = "[✓]"
cross_box = "[✗]"
info_box = "[i]"
# Monkeypatch sh to bash, if they ever support non hard code /bin/sh this can go away
# https://github.com/pytest-dev/pytest-testinfra/blob/master/testinfra/backend/docker.py
def run_bash(self, command, *args, **kwargs):
cmd = self.get_command(command, *args)
if self.user is not None:
out = self.run_local(
"docker exec -u %s %s /bin/bash -c %s", self.user, self.name, cmd
)
else:
out = self.run_local("docker exec %s /bin/bash -c %s", self.name, cmd)
out.command = self.encode(cmd)
return out
testinfra.backend.docker.DockerBackend.run = run_bash
@pytest.fixture
def host():
# run a container
docker_id = (
subprocess.check_output(["docker", "run", "-t", "-d", "--cap-add=ALL", IMAGE])
.decode()
.strip()
)
# return a testinfra connection to the container
docker_host = testinfra.get_host("docker://" + docker_id)
yield docker_host
# at the end of the test suite, destroy the container
subprocess.check_call(["docker", "rm", "-f", docker_id])
# Helper functions
def mock_command(script, args, container):
"""
Allows for setup of commands we don't really want to have to run for real
in unit tests
"""
full_script_path = "/usr/local/bin/{}".format(script)
mock_script = dedent(r"""\
#!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script}
case "\$1" in""".format(script=script))
for k, v in args.items():
case = dedent("""
{arg})
echo {res}
exit {retcode}
;;""".format(arg=k, res=v[0], retcode=v[1]))
mock_script += case
mock_script += dedent("""
esac""")
container.run(
"""
cat <<EOF> {script}\n{content}\nEOF
chmod +x {script}
rm -f /var/log/{scriptlog}""".format(
script=full_script_path, content=mock_script, scriptlog=script
)
)
def mock_command_passthrough(script, args, container):
"""
Per other mock_command* functions, allows intercepting of commands we don't want to run for real
in unit tests, however also allows only specific arguments to be mocked. Anything not defined will
be passed through to the actual command.
Example use-case: mocking `git pull` but still allowing `git clone` to work as intended
"""
orig_script_path = container.check_output("command -v {}".format(script))
full_script_path = "/usr/local/bin/{}".format(script)
mock_script = dedent(r"""\
#!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script}
case "\$1" in""".format(script=script))
for k, v in args.items():
case = dedent("""
{arg})
echo {res}
exit {retcode}
;;""".format(arg=k, res=v[0], retcode=v[1]))
mock_script += case
mock_script += dedent(r"""
*)
{orig_script_path} "\$@"
;;""".format(orig_script_path=orig_script_path))
mock_script += dedent("""
esac""")
container.run(
"""
cat <<EOF> {script}\n{content}\nEOF
chmod +x {script}
rm -f /var/log/{scriptlog}""".format(
script=full_script_path, content=mock_script, scriptlog=script
)
)
def mock_command_run(script, args, container):
"""
Allows for setup of commands we don't really want to have to run for real
in unit tests
"""
full_script_path = "/usr/local/bin/{}".format(script)
mock_script = dedent(r"""\
#!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script}
case "\$1 \$2" in""".format(script=script))
for k, v in args.items():
case = dedent("""
\"{arg}\")
echo {res}
exit {retcode}
;;""".format(arg=k, res=v[0], retcode=v[1]))
mock_script += case
mock_script += dedent(r"""
esac""")
container.run(
"""
cat <<EOF> {script}\n{content}\nEOF
chmod +x {script}
rm -f /var/log/{scriptlog}""".format(
script=full_script_path, content=mock_script, scriptlog=script
)
)
def mock_command_2(script, args, container):
"""
Allows for setup of commands we don't really want to have to run for real
in unit tests
"""
full_script_path = "/usr/local/bin/{}".format(script)
mock_script = dedent(r"""\
#!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script}
case "\$1 \$2" in""".format(script=script))
for k, v in args.items():
case = dedent("""
\"{arg}\")
echo \"{res}\"
exit {retcode}
;;""".format(arg=k, res=v[0], retcode=v[1]))
mock_script += case
mock_script += dedent(r"""
esac""")
container.run(
"""
cat <<EOF> {script}\n{content}\nEOF
chmod +x {script}
rm -f /var/log/{scriptlog}""".format(
script=full_script_path, content=mock_script, scriptlog=script
)
)
def run_script(Pihole, script):
result = Pihole.run(script)
assert result.rc == 0
return result

View File

@@ -1,106 +0,0 @@
#!/usr/bin/env bash
# Mock command helpers for BATS tests.
#
# These are the BATS equivalents of the mock_command* functions in conftest.py.
# Each function writes a bash case-statement script to /usr/local/bin/<name>
# inside the container, allowing tests to intercept command invocations.
#
# Usage:
# mock_command CONTAINER SCRIPT ARG1 OUTPUT1 RC1 [ARG2 OUTPUT2 RC2 ...]
# mock_command_2 CONTAINER SCRIPT ARG1 OUTPUT1 RC1 [ARG2 OUTPUT2 RC2 ...]
# mock_command_passthrough CONTAINER SCRIPT ARG1 OUTPUT1 RC1 [...]
#
# mock_command: matches on $1 (first argument); unquoted case pattern
# mock_command_2: matches on "$1 $2" (first two args joined); quoted pattern
# mock_command_passthrough: like mock_command but falls through to real binary
#
# Use '*' as ARG for a catch-all case (only works in mock_command and
# mock_command_passthrough; in mock_command_2 it matches the literal string '*').
#
# Content is transferred to the container via base64 to avoid quoting issues.
_write_mock_to_container() {
local container="$1" script_name="$2" script_content="$3"
# base64 alphabet is [A-Za-z0-9+/=] — safe to single-quote in the shell
local encoded
encoded=$(printf '%s' "$script_content" | base64 | tr -d '\n')
docker exec "$container" bash -c \
"printf '%s' '${encoded}' | base64 -d > /usr/local/bin/${script_name} && chmod +x /usr/local/bin/${script_name} && rm -f /var/log/${script_name}"
}
# mock_command — matches on $1
mock_command() {
local container="$1" script_name="$2"
shift 2
local script
script='#!/bin/bash -e'$'\n'
script+="echo \"\$0 \$@\" >> /var/log/${script_name}"$'\n'
script+='case "$1" in'$'\n'
while (( $# >= 3 )); do
local arg="$1" output="$2" rc="$3"
shift 3
script+=" ${arg})"$'\n'
script+=" echo ${output}"$'\n'
script+=" exit ${rc}"$'\n'
script+=" ;;"$'\n'
done
script+='esac'$'\n'
_write_mock_to_container "$container" "$script_name" "$script"
}
# mock_command_2 — matches on "$1 $2" (quoted pattern, quoted echo output)
mock_command_2() {
local container="$1" script_name="$2"
shift 2
local script
script='#!/bin/bash -e'$'\n'
script+="echo \"\$0 \$@\" >> /var/log/${script_name}"$'\n'
script+='case "$1 $2" in'$'\n'
while (( $# >= 3 )); do
local arg="$1" output="$2" rc="$3"
shift 3
script+=" \"${arg}\")"$'\n'
script+=" echo \"${output}\""$'\n'
script+=" exit ${rc}"$'\n'
script+=" ;;"$'\n'
done
script+='esac'$'\n'
_write_mock_to_container "$container" "$script_name" "$script"
}
# mock_command_passthrough — matches on $1; falls through to real binary for
# unmatched arguments
mock_command_passthrough() {
local container="$1" script_name="$2"
shift 2
# Find the real binary path before we shadow it
local orig_path
orig_path=$(docker exec "$container" bash -c "command -v ${script_name}")
local script
script='#!/bin/bash -e'$'\n'
script+="echo \"\$0 \$@\" >> /var/log/${script_name}"$'\n'
script+='case "$1" in'$'\n'
while (( $# >= 3 )); do
local arg="$1" output="$2" rc="$3"
shift 3
script+=" ${arg})"$'\n'
script+=" echo ${output}"$'\n'
script+=" exit ${rc}"$'\n'
script+=" ;;"$'\n'
done
script+=' *)'$'\n'
script+=" ${orig_path} \"\$@\""$'\n'
script+=' ;;'$'\n'
script+='esac'$'\n'
_write_mock_to_container "$container" "$script_name" "$script"
}

6
test/requirements.txt Normal file
View File

@@ -0,0 +1,6 @@
pyyaml == 6.0.3
pytest == 9.0.2
pytest-xdist == 3.8.0
pytest-testinfra == 10.2.2
tox == 4.35.0
pytest-clarity == 1.0.1

View File

@@ -1,91 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# ---------------------------------------------------------------------------
# Distro selection
# ---------------------------------------------------------------------------
if [[ -z "${DISTRO:-}" ]]; then
echo "Error: DISTRO is required."
echo "Example: DISTRO=debian_12 bash test/run.sh"
echo ""
echo "Available distros:"
ls _*.Dockerfile | sed 's/^_//;s/\.Dockerfile$//' | sort
exit 1
fi
DOCKERFILE="_${DISTRO}.Dockerfile"
if [[ ! -f "$DOCKERFILE" ]]; then
echo "Error: Dockerfile not found: $DOCKERFILE"
exit 1
fi
# Determine distro family to select which test files to run.
# rhel: CentOS/Fedora — includes SELinux tests
# alpine: Alpine Linux
# debian: Debian/Ubuntu (default)
distro_family() {
case "$1" in
centos_* | fedora_*) echo "rhel" ;;
alpine_*) echo "alpine" ;;
*) echo "debian" ;;
esac
}
DISTRO_FAMILY=$(distro_family "$DISTRO")
# ---------------------------------------------------------------------------
# Build the test image
# ---------------------------------------------------------------------------
IMAGE_TAG="pihole_test:${DISTRO}"
docker buildx build \
--load \
--progress plain \
-f "$DOCKERFILE" \
-t "$IMAGE_TAG" \
../
# ---------------------------------------------------------------------------
# Install BATS and helper libraries (on-demand, not committed)
# ---------------------------------------------------------------------------
mkdir -p libs
if [[ ! -d libs/bats ]]; then
echo "Cloning bats-core..."
git clone --depth=1 --quiet https://github.com/bats-core/bats-core libs/bats
fi
if [[ ! -d libs/bats-support ]]; then
echo "Cloning bats-support..."
git clone --depth=1 --quiet https://github.com/bats-core/bats-support libs/bats-support
fi
if [[ ! -d libs/bats-assert ]]; then
echo "Cloning bats-assert..."
git clone --depth=1 --quiet https://github.com/bats-core/bats-assert libs/bats-assert
fi
BATS="${BATS:-libs/bats/bin/bats}"
# ---------------------------------------------------------------------------
# Run tests
# ---------------------------------------------------------------------------
export IMAGE_TAG DISTRO DISTRO_FAMILY
TEST_FILES=(
test_automated_install.bats
test_ftl.bats
test_network.bats
test_utils.bats
)
[[ "$DISTRO_FAMILY" == "rhel" ]] && TEST_FILES+=(test_selinux.bats)
# Use pretty output only when stdout is a real terminal; fall back to TAP in CI.
# Parallelise across files with --jobs when GNU parallel is available.
BATS_FLAGS=()
[[ -t 1 ]] && BATS_FLAGS+=("-p")
command -v parallel > /dev/null 2>&1 && BATS_FLAGS+=("--jobs" "$(nproc)")
"$BATS" "${BATS_FLAGS[@]}" "${TEST_FILES[@]}"

7
test/setup.py Normal file
View File

@@ -0,0 +1,7 @@
from setuptools import setup
setup(
py_modules=[],
setup_requires=["pytest-runner"],
tests_require=["pytest"],
)

View File

@@ -0,0 +1,472 @@
import pytest
from textwrap import dedent
import re
from .conftest import (
tick_box,
info_box,
cross_box,
mock_command,
mock_command_2,
mock_command_passthrough,
)
FTL_BRANCH = "development"
def test_supported_package_manager(host):
"""
confirm installer exits when no supported package manager found
"""
# break supported package managers
host.run("rm -rf /usr/bin/apt-get")
host.run("rm -rf /usr/bin/rpm")
host.run("rm -rf /sbin/apk")
package_manager_detect = host.run("""
source /opt/pihole/basic-install.sh
package_manager_detect
""")
expected_stdout = cross_box + " No supported package manager found"
assert expected_stdout in package_manager_detect.stdout
# assert package_manager_detect.rc == 1
def test_selinux_not_detected(host):
"""
confirms installer continues when SELinux configuration file does not exist
"""
check_selinux = host.run("""
rm -f /etc/selinux/config
source /opt/pihole/basic-install.sh
checkSelinux
""")
expected_stdout = info_box + " SELinux not detected"
assert expected_stdout in check_selinux.stdout
assert check_selinux.rc == 0
def get_directories_recursive(host, directory):
if directory is None:
return directory
# returns all non-hidden subdirs of 'directory'
dirs_raw = host.run("find {} -type d -not -path '*/.*'".format(directory))
dirs = list(filter(bool, dirs_raw.stdout.splitlines()))
return dirs
def test_installPihole_fresh_install_readableFiles(host):
"""
confirms all necessary files are readable by pihole user
"""
# dialog returns Cancel for user prompt
mock_command("dialog", {"*": ("", "0")}, host)
# mock git pull
mock_command_passthrough("git", {"pull": ("", "0")}, host)
# mock systemctl to not start FTL
mock_command_2(
"systemctl",
{
"enable pihole-FTL": ("", "0"),
"restart pihole-FTL": ("", "0"),
"start pihole-FTL": ("", "0"),
"*": ('echo "systemctl call with $@"', "0"),
},
host,
)
mock_command_2(
"rc-service",
{
"rc-service pihole-FTL enable": ("", "0"),
"rc-service pihole-FTL restart": ("", "0"),
"rc-service pihole-FTL start": ("", "0"),
"*": ('echo "rc-service call with $@"', "0"),
},
host,
)
# try to install man
host.run("command -v apt-get > /dev/null && apt-get install -qq man")
host.run("command -v dnf > /dev/null && dnf install -y man")
host.run("command -v yum > /dev/null && yum install -y man")
host.run("command -v apk > /dev/null && apk add mandoc man-pages")
# Workaround to get FTLv6 installed until it reaches master branch
host.run('echo "' + FTL_BRANCH + '" > /etc/pihole/ftlbranch')
install = host.run("""
export TERM=xterm
export DEBIAN_FRONTEND=noninteractive
umask 0027
runUnattended=true
source /opt/pihole/basic-install.sh > /dev/null
runUnattended=true
main
/opt/pihole/pihole-FTL-prestart.sh
""")
assert 0 == install.rc
maninstalled = True
if (info_box + " man not installed") in install.stdout:
maninstalled = False
if (info_box + " man pages not installed") in install.stdout:
maninstalled = False
piholeuser = "pihole"
exit_status_success = 0
test_cmd = 'su -s /bin/bash -c "test -{0} {1}" -p {2}'
# check files in /etc/pihole for read, write and execute permission
check_etc = test_cmd.format("r", "/etc/pihole", piholeuser)
actual_rc = host.run(check_etc).rc
assert exit_status_success == actual_rc
check_etc = test_cmd.format("x", "/etc/pihole", piholeuser)
actual_rc = host.run(check_etc).rc
assert exit_status_success == actual_rc
# readable and writable dhcp.leases
check_leases = test_cmd.format("r", "/etc/pihole/dhcp.leases", piholeuser)
actual_rc = host.run(check_leases).rc
assert exit_status_success == actual_rc
check_leases = test_cmd.format("w", "/etc/pihole/dhcp.leases", piholeuser)
actual_rc = host.run(check_leases).rc
# readable install.log
check_install = test_cmd.format("r", "/etc/pihole/install.log", piholeuser)
actual_rc = host.run(check_install).rc
assert exit_status_success == actual_rc
# readable versions
check_localversion = test_cmd.format("r", "/etc/pihole/versions", piholeuser)
actual_rc = host.run(check_localversion).rc
assert exit_status_success == actual_rc
# readable macvendor.db
check_macvendor = test_cmd.format("r", "/etc/pihole/macvendor.db", piholeuser)
actual_rc = host.run(check_macvendor).rc
assert exit_status_success == actual_rc
# check readable and executable /etc/init.d/pihole-FTL
check_init = test_cmd.format("x", "/etc/init.d/pihole-FTL", piholeuser)
actual_rc = host.run(check_init).rc
assert exit_status_success == actual_rc
check_init = test_cmd.format("r", "/etc/init.d/pihole-FTL", piholeuser)
actual_rc = host.run(check_init).rc
assert exit_status_success == actual_rc
# check readable and executable manpages
if maninstalled is True:
check_man = test_cmd.format("x", "/usr/local/share/man", piholeuser)
actual_rc = host.run(check_man).rc
assert exit_status_success == actual_rc
check_man = test_cmd.format("r", "/usr/local/share/man", piholeuser)
actual_rc = host.run(check_man).rc
assert exit_status_success == actual_rc
check_man = test_cmd.format("x", "/usr/local/share/man/man8", piholeuser)
actual_rc = host.run(check_man).rc
assert exit_status_success == actual_rc
check_man = test_cmd.format("r", "/usr/local/share/man/man8", piholeuser)
actual_rc = host.run(check_man).rc
assert exit_status_success == actual_rc
check_man = test_cmd.format(
"r", "/usr/local/share/man/man8/pihole.8", piholeuser
)
actual_rc = host.run(check_man).rc
assert exit_status_success == actual_rc
# check not readable cron file
check_sudo = test_cmd.format("x", "/etc/cron.d/", piholeuser)
actual_rc = host.run(check_sudo).rc
assert exit_status_success == actual_rc
check_sudo = test_cmd.format("r", "/etc/cron.d/", piholeuser)
actual_rc = host.run(check_sudo).rc
assert exit_status_success == actual_rc
check_sudo = test_cmd.format("r", "/etc/cron.d/pihole", piholeuser)
actual_rc = host.run(check_sudo).rc
assert exit_status_success == actual_rc
directories = get_directories_recursive(host, "/etc/.pihole/")
for directory in directories:
check_pihole = test_cmd.format("r", directory, piholeuser)
actual_rc = host.run(check_pihole).rc
check_pihole = test_cmd.format("x", directory, piholeuser)
actual_rc = host.run(check_pihole).rc
findfiles = 'find "{}" -maxdepth 1 -type f -exec echo {{}} \\;;'
filelist = host.run(findfiles.format(directory))
files = list(filter(bool, filelist.stdout.splitlines()))
for file in files:
check_pihole = test_cmd.format("r", file, piholeuser)
actual_rc = host.run(check_pihole).rc
def test_update_package_cache_success_no_errors(host):
"""
confirms package cache was updated without any errors
"""
updateCache = host.run("""
source /opt/pihole/basic-install.sh
package_manager_detect
update_package_cache
""")
expected_stdout = tick_box + " Update local cache of available packages"
assert expected_stdout in updateCache.stdout
assert "error" not in updateCache.stdout.lower()
def test_update_package_cache_failure_no_errors(host):
"""
confirms package cache was not updated
"""
mock_command("apt-get", {"update": ("", "1")}, host)
updateCache = host.run("""
source /opt/pihole/basic-install.sh
package_manager_detect
update_package_cache
""")
expected_stdout = cross_box + " Update local cache of available packages"
assert expected_stdout in updateCache.stdout
assert "Error: Unable to update package cache." in updateCache.stdout
@pytest.mark.parametrize(
"arch,detected_string,supported",
[
("aarch64", "AArch64 (64 Bit ARM)", True),
("armv6", "ARMv6", True),
("armv7l", "ARMv7 (or newer)", True),
("armv7", "ARMv7 (or newer)", True),
("armv8a", "ARMv7 (or newer)", True),
("x86_64", "x86_64", True),
("riscv64", "riscv64", True),
("mips", "mips", False),
],
)
def test_FTL_detect_no_errors(host, arch, detected_string, supported):
"""
confirms only correct package is downloaded for FTL engine
"""
# mock uname to return passed platform
mock_command("uname", {"-m": (arch, "0")}, host)
# mock readelf to respond with passed CPU architecture
mock_command_2(
"readelf",
{
"-A /bin/sh": ("Tag_CPU_arch: " + arch, "0"),
"-A /usr/bin/sh": ("Tag_CPU_arch: " + arch, "0"),
"-A /usr/sbin/sh": ("Tag_CPU_arch: " + arch, "0"),
},
host,
)
host.run('echo "' + FTL_BRANCH + '" > /etc/pihole/ftlbranch')
detectPlatform = host.run("""
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=$(get_binary_name)
binary="pihole-FTL${funcOutput##*pihole-FTL}"
theRest="${funcOutput%pihole-FTL*}"
FTLdetect "${binary}" "${theRest}"
""")
if supported:
expected_stdout = info_box + " FTL Checks..."
assert expected_stdout in detectPlatform.stdout
expected_stdout = tick_box + " Detected " + detected_string + " architecture"
assert expected_stdout in detectPlatform.stdout
expected_stdout = tick_box + " Downloading and Installing FTL"
assert expected_stdout in detectPlatform.stdout
else:
expected_stdout = (
"Not able to detect architecture (unknown: " + detected_string + ")"
)
assert expected_stdout in detectPlatform.stdout
def test_FTL_development_binary_installed_and_responsive_no_errors(host):
"""
confirms FTL development binary is copied and functional in installed location
"""
host.run('echo "' + FTL_BRANCH + '" > /etc/pihole/ftlbranch')
host.run("""
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=$(get_binary_name)
binary="pihole-FTL${funcOutput##*pihole-FTL}"
theRest="${funcOutput%pihole-FTL*}"
FTLdetect "${binary}" "${theRest}"
""")
version_check = host.run("""
VERSION=$(pihole-FTL version)
echo ${VERSION:0:1}
""")
expected_stdout = "v"
assert expected_stdout in version_check.stdout
def test_IPv6_only_link_local(host):
"""
confirms IPv6 blocking is disabled for Link-local address
"""
# mock ip -6 address to return Link-local address
mock_command_2(
"ip",
{"-6 address": ("inet6 fe80::d210:52fa:fe00:7ad7/64 scope link", "0")},
host,
)
detectPlatform = host.run("""
source /opt/pihole/basic-install.sh
find_IPv6_information
""")
expected_stdout = "Unable to find IPv6 ULA/GUA address"
assert expected_stdout in detectPlatform.stdout
def test_IPv6_only_ULA(host):
"""
confirms IPv6 blocking is enabled for ULA addresses
"""
# mock ip -6 address to return ULA address
mock_command_2(
"ip",
{
"-6 address": (
"inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global",
"0",
)
},
host,
)
detectPlatform = host.run("""
source /opt/pihole/basic-install.sh
find_IPv6_information
""")
expected_stdout = "Found IPv6 ULA address"
assert expected_stdout in detectPlatform.stdout
def test_IPv6_only_GUA(host):
"""
confirms IPv6 blocking is enabled for GUA addresses
"""
# mock ip -6 address to return GUA address
mock_command_2(
"ip",
{
"-6 address": (
"inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global",
"0",
)
},
host,
)
detectPlatform = host.run("""
source /opt/pihole/basic-install.sh
find_IPv6_information
""")
expected_stdout = "Found IPv6 GUA address"
assert expected_stdout in detectPlatform.stdout
def test_IPv6_GUA_ULA_test(host):
"""
confirms IPv6 blocking is enabled for GUA and ULA addresses
"""
# mock ip -6 address to return GUA and ULA addresses
mock_command_2(
"ip",
{
"-6 address": (
"inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global\n"
"inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global",
"0",
)
},
host,
)
detectPlatform = host.run("""
source /opt/pihole/basic-install.sh
find_IPv6_information
""")
expected_stdout = "Found IPv6 ULA address"
assert expected_stdout in detectPlatform.stdout
def test_IPv6_ULA_GUA_test(host):
"""
confirms IPv6 blocking is enabled for GUA and ULA addresses
"""
# mock ip -6 address to return ULA and GUA addresses
mock_command_2(
"ip",
{
"-6 address": (
"inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global\n"
"inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global",
"0",
)
},
host,
)
detectPlatform = host.run("""
source /opt/pihole/basic-install.sh
find_IPv6_information
""")
expected_stdout = "Found IPv6 ULA address"
assert expected_stdout in detectPlatform.stdout
def test_validate_ip(host):
"""
Tests valid_ip for various IP addresses
"""
def test_address(addr, success=True):
output = host.run("""
source /opt/pihole/basic-install.sh
valid_ip "{addr}"
""".format(addr=addr))
assert output.rc == 0 if success else 1
test_address("192.168.1.1")
test_address("127.0.0.1")
test_address("255.255.255.255")
test_address("255.255.255.256", False)
test_address("255.255.256.255", False)
test_address("255.256.255.255", False)
test_address("256.255.255.255", False)
test_address("1092.168.1.1", False)
test_address("not an IP", False)
test_address("8.8.8.8#", False)
test_address("8.8.8.8#0")
test_address("8.8.8.8#1")
test_address("8.8.8.8#42")
test_address("8.8.8.8#888")
test_address("8.8.8.8#1337")
test_address("8.8.8.8#65535")
test_address("8.8.8.8#65536", False)
test_address("8.8.8.8#-1", False)
test_address("00.0.0.0", False)
test_address("010.0.0.0", False)
test_address("001.0.0.0", False)
test_address("0.0.0.0#00", False)
test_address("0.0.0.0#01", False)
test_address("0.0.0.0#001", False)
test_address("0.0.0.0#0001", False)
test_address("0.0.0.0#00001", False)
def test_package_manager_has_pihole_deps(host):
"""Confirms OS is able to install the required packages for Pi-hole"""
mock_command("dialog", {"*": ("", "0")}, host)
output = host.run("""
source /opt/pihole/basic-install.sh
package_manager_detect
update_package_cache
build_dependency_package
install_dependent_packages
""")
assert "No package" not in output.stdout
assert output.rc == 0
def test_meta_package_uninstall(host):
"""Confirms OS is able to install and uninstall the Pi-hole meta package"""
mock_command("dialog", {"*": ("", "0")}, host)
install = host.run("""
source /opt/pihole/basic-install.sh
package_manager_detect
update_package_cache
build_dependency_package
install_dependent_packages
""")
assert install.rc == 0
uninstall = host.run("""
source /opt/pihole/uninstall.sh
removeMetaPackage
""")
assert uninstall.rc == 0

50
test/test_any_utils.py Normal file
View File

@@ -0,0 +1,50 @@
def test_key_val_replacement_works(host):
"""Confirms addOrEditKeyValPair either adds or replaces a key value pair in a given file"""
host.run("""
source /opt/pihole/utils.sh
touch ./testoutput
addOrEditKeyValPair "./testoutput" "KEY_ONE" "value1"
addOrEditKeyValPair "./testoutput" "KEY_TWO" "value2"
addOrEditKeyValPair "./testoutput" "KEY_ONE" "value3"
addOrEditKeyValPair "./testoutput" "KEY_FOUR" "value4"
""")
output = host.run("""
cat ./testoutput
""")
expected_stdout = "KEY_ONE=value3\nKEY_TWO=value2\nKEY_FOUR=value4\n"
assert expected_stdout == output.stdout
def test_getFTLPID_default(host):
"""Confirms getFTLPID returns the default value if FTL is not running"""
output = host.run("""
source /opt/pihole/utils.sh
getFTLPID
""")
expected_stdout = "-1\n"
assert expected_stdout == output.stdout
def test_setFTLConfigValue_getFTLConfigValue(host):
"""
Confirms getFTLConfigValue works (also assumes setFTLConfigValue works)
Requires FTL to be installed, so we do that first
(taken from test_FTL_development_binary_installed_and_responsive_no_errors)
"""
host.run("""
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=$(get_binary_name)
echo "development" > /etc/pihole/ftlbranch
binary="pihole-FTL${funcOutput##*pihole-FTL}"
theRest="${funcOutput%pihole-FTL*}"
FTLdetect "${binary}" "${theRest}"
""")
output = host.run("""
source /opt/pihole/utils.sh
setFTLConfigValue "dns.upstreams" '["9.9.9.9"]' > /dev/null
getFTLConfigValue "dns.upstreams"
""")
assert "[ 9.9.9.9 ]" in output.stdout

View File

@@ -1,188 +0,0 @@
#!/usr/bin/env bats
# Core installer tests — package manager, cache, fresh install, dependencies
load 'libs/bats-support/load'
load 'libs/bats-assert/load'
load 'helpers/mocks'
TICK="[✓]"
CROSS="[✗]"
INFO="[i]"
FTL_BRANCH="development"
CID=""
setup() {
CID=$(docker run -d -t --cap-add=ALL "$IMAGE_TAG")
}
teardown() {
if [[ -n "$CID" ]]; then
docker rm -f "$CID" > /dev/null 2>&1 || true
fi
}
# ---------------------------------------------------------------------------
@test "installer exits when no supported package manager found" {
docker exec "$CID" bash -c "rm -rf /usr/bin/apt-get /usr/bin/rpm /sbin/apk"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
package_manager_detect
"
assert_output --partial "${CROSS} No supported package manager found"
}
@test "installer continues when SELinux config file does not exist" {
run docker exec "$CID" bash -c "
rm -f /etc/selinux/config
source /opt/pihole/basic-install.sh
checkSelinux
"
assert_output --partial "${INFO} SELinux not detected"
assert_success
}
@test "fresh install: all necessary files are readable by pihole user" {
mock_command "$CID" dialog "*" "" "0"
mock_command_passthrough "$CID" git "pull" "" "0"
mock_command_2 "$CID" systemctl \
"enable pihole-FTL" "" "0" \
"restart pihole-FTL" "" "0" \
"start pihole-FTL" "" "0"
mock_command_2 "$CID" rc-service \
"pihole-FTL enable" "" "0" \
"pihole-FTL restart" "" "0" \
"pihole-FTL start" "" "0"
# Install man pages if available (best-effort)
docker exec "$CID" bash -c "command -v apt-get > /dev/null && apt-get install -qq man" || true
docker exec "$CID" bash -c "command -v dnf > /dev/null && dnf install -y man" || true
docker exec "$CID" bash -c "command -v yum > /dev/null && yum install -y man" || true
docker exec "$CID" bash -c "command -v apk > /dev/null && apk add mandoc man-pages" || true
docker exec "$CID" bash -c "echo '${FTL_BRANCH}' > /etc/pihole/ftlbranch"
run docker exec "$CID" bash -c "
export TERM=xterm
export DEBIAN_FRONTEND=noninteractive
umask 0027
runUnattended=true
source /opt/pihole/basic-install.sh > /dev/null
runUnattended=true
main
/opt/pihole/pihole-FTL-prestart.sh
"
assert_success
# Detect whether man was installed
local maninstalled=true
if [[ "$output" == *"${INFO} man not installed"* ]] || [[ "$output" == *"${INFO} man pages not installed"* ]]; then
maninstalled=false
fi
local piholeuser="pihole"
_check_perm() { docker exec "$CID" bash -c "su -s /bin/bash -c 'test -${1} ${2}' -p ${piholeuser}"; }
# /etc/pihole
run _check_perm r /etc/pihole; assert_success
run _check_perm x /etc/pihole; assert_success
# /etc/pihole/dhcp.leases
run _check_perm r /etc/pihole/dhcp.leases; assert_success
# /etc/pihole/install.log
run _check_perm r /etc/pihole/install.log; assert_success
# /etc/pihole/versions
run _check_perm r /etc/pihole/versions; assert_success
# /etc/pihole/macvendor.db
run _check_perm r /etc/pihole/macvendor.db; assert_success
# /etc/init.d/pihole-FTL
run _check_perm x /etc/init.d/pihole-FTL; assert_success
run _check_perm r /etc/init.d/pihole-FTL; assert_success
# man pages (if installed)
if [[ "$maninstalled" == "true" ]]; then
run _check_perm x /usr/local/share/man; assert_success
run _check_perm r /usr/local/share/man; assert_success
run _check_perm x /usr/local/share/man/man8; assert_success
run _check_perm r /usr/local/share/man/man8; assert_success
run _check_perm r /usr/local/share/man/man8/pihole.8; assert_success
fi
# /etc/cron.d
run _check_perm x /etc/cron.d/; assert_success
run _check_perm r /etc/cron.d/; assert_success
run _check_perm r /etc/cron.d/pihole; assert_success
# All files and directories under /etc/.pihole/
local dirs
dirs=$(docker exec "$CID" bash -c "find /etc/.pihole/ -type d -not -path '*/.*'" 2>/dev/null || true)
while IFS= read -r dir; do
[[ -z "$dir" ]] && continue
run _check_perm r "$dir"; assert_success
run _check_perm x "$dir"; assert_success
local files
files=$(docker exec "$CID" bash -c "find '${dir}' -maxdepth 1 -type f -exec echo {} \\;" 2>/dev/null || true)
while IFS= read -r file; do
[[ -z "$file" ]] && continue
run _check_perm r "$file"; assert_success
done <<< "$files"
done <<< "$dirs"
}
@test "package cache update succeeds without errors" {
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
package_manager_detect
update_package_cache
"
assert_output --partial "${TICK} Update local cache of available packages"
refute_output --partial "error"
}
@test "package cache update reports failure correctly" {
mock_command "$CID" apt-get "update" "" "1"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
package_manager_detect
update_package_cache
"
assert_output --partial "${CROSS} Update local cache of available packages"
assert_output --partial "Error: Unable to update package cache."
}
@test "OS can install required Pi-hole dependency packages" {
mock_command "$CID" dialog "*" "" "0"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
package_manager_detect
update_package_cache
build_dependency_package
install_dependent_packages
"
refute_output --partial "No package"
assert_success
}
@test "OS can install and uninstall the Pi-hole meta package" {
mock_command "$CID" dialog "*" "" "0"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
package_manager_detect
update_package_cache
build_dependency_package
install_dependent_packages
"
assert_success
run docker exec "$CID" bash -c "
source /opt/pihole/uninstall.sh
removeMetaPackage
"
assert_success
}

View File

@@ -0,0 +1,65 @@
from .conftest import (
tick_box,
cross_box,
mock_command,
)
def mock_selinux_config(state, host):
"""
Creates a mock SELinux config file with expected content
"""
# validate state string
valid_states = ["enforcing", "permissive", "disabled"]
assert state in valid_states
# getenforce returns the running state of SELinux
mock_command("getenforce", {"*": (state.capitalize(), "0")}, host)
# create mock configuration with desired content
host.run("""
mkdir /etc/selinux
echo "SELINUX={state}" > /etc/selinux/config
""".format(state=state.lower()))
def test_selinux_enforcing_exit(host):
"""
confirms installer prompts to exit when SELinux is Enforcing by default
"""
mock_selinux_config("enforcing", host)
check_selinux = host.run("""
source /opt/pihole/basic-install.sh
checkSelinux
""")
expected_stdout = cross_box + " Current SELinux: enforcing"
assert expected_stdout in check_selinux.stdout
expected_stdout = "SELinux Enforcing detected, exiting installer"
assert expected_stdout in check_selinux.stdout
assert check_selinux.rc == 1
def test_selinux_permissive(host):
"""
confirms installer continues when SELinux is Permissive
"""
mock_selinux_config("permissive", host)
check_selinux = host.run("""
source /opt/pihole/basic-install.sh
checkSelinux
""")
expected_stdout = tick_box + " Current SELinux: permissive"
assert expected_stdout in check_selinux.stdout
assert check_selinux.rc == 0
def test_selinux_disabled(host):
"""
confirms installer continues when SELinux is Disabled
"""
mock_selinux_config("disabled", host)
check_selinux = host.run("""
source /opt/pihole/basic-install.sh
checkSelinux
""")
expected_stdout = tick_box + " Current SELinux: disabled"
assert expected_stdout in check_selinux.stdout
assert check_selinux.rc == 0

View File

@@ -1,104 +0,0 @@
#!/usr/bin/env bats
# FTL architecture detection and binary installation tests
load 'libs/bats-support/load'
load 'libs/bats-assert/load'
load 'helpers/mocks'
TICK="[✓]"
INFO="[i]"
FTL_BRANCH="development"
CID=""
setup() {
CID=$(docker run -d -t --cap-add=ALL "$IMAGE_TAG")
}
teardown() {
if [[ -n "$CID" ]]; then
docker rm -f "$CID" > /dev/null 2>&1 || true
fi
}
# ---------------------------------------------------------------------------
# FTL architecture detection — one @test per arch (replaces parametrize)
# ---------------------------------------------------------------------------
_test_ftl_arch() {
local arch="$1" detected_string="$2" supported="$3"
mock_command "$CID" uname "-m" "$arch" "0"
mock_command_2 "$CID" readelf \
"-A /bin/sh" "Tag_CPU_arch: ${arch}" "0" \
"-A /usr/bin/sh" "Tag_CPU_arch: ${arch}" "0" \
"-A /usr/sbin/sh" "Tag_CPU_arch: ${arch}" "0"
docker exec "$CID" bash -c "echo '${FTL_BRANCH}' > /etc/pihole/ftlbranch"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=\$(get_binary_name)
binary=\"pihole-FTL\${funcOutput##*pihole-FTL}\"
theRest=\"\${funcOutput%pihole-FTL*}\"
FTLdetect \"\${binary}\" \"\${theRest}\"
"
if [[ "$supported" == "true" ]]; then
assert_output --partial "${INFO} FTL Checks..."
assert_output --partial "${TICK} Detected ${detected_string} architecture"
assert_output --partial "${TICK} Downloading and Installing FTL"
else
assert_output --partial "Not able to detect architecture (unknown: ${detected_string})"
fi
}
@test "FTL detects aarch64 architecture" {
_test_ftl_arch "aarch64" "AArch64 (64 Bit ARM)" "true"
}
@test "FTL detects ARMv6 architecture" {
_test_ftl_arch "armv6" "ARMv6" "true"
}
@test "FTL detects ARMv7l architecture" {
_test_ftl_arch "armv7l" "ARMv7 (or newer)" "true"
}
@test "FTL detects ARMv7 architecture" {
_test_ftl_arch "armv7" "ARMv7 (or newer)" "true"
}
@test "FTL detects ARMv8a architecture" {
_test_ftl_arch "armv8a" "ARMv7 (or newer)" "true"
}
@test "FTL detects x86_64 architecture" {
_test_ftl_arch "x86_64" "x86_64" "true"
}
@test "FTL detects riscv64 architecture" {
_test_ftl_arch "riscv64" "riscv64" "true"
}
@test "FTL reports unsupported architecture" {
_test_ftl_arch "mips" "mips" "false"
}
@test "FTL development binary is installed and responsive" {
docker exec "$CID" bash -c "echo '${FTL_BRANCH}' > /etc/pihole/ftlbranch"
docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=\$(get_binary_name)
binary=\"pihole-FTL\${funcOutput##*pihole-FTL}\"
theRest=\"\${funcOutput%pihole-FTL*}\"
FTLdetect \"\${binary}\" \"\${theRest}\"
"
run docker exec "$CID" bash -c '
VERSION=$(pihole-FTL version)
echo "${VERSION:0:1}"
'
assert_output --partial "v"
}

View File

@@ -1,116 +0,0 @@
#!/usr/bin/env bats
# Network detection tests — IPv6 address detection and IP validation
load 'libs/bats-support/load'
load 'libs/bats-assert/load'
load 'helpers/mocks'
CID=""
setup() {
CID=$(docker run -d -t --cap-add=ALL "$IMAGE_TAG")
}
teardown() {
if [[ -n "$CID" ]]; then
docker rm -f "$CID" > /dev/null 2>&1 || true
fi
}
# ---------------------------------------------------------------------------
# IPv6 detection
# ---------------------------------------------------------------------------
@test "IPv6 link-local only: blocking disabled" {
mock_command_2 "$CID" ip \
"-6 address" "inet6 fe80::d210:52fa:fe00:7ad7/64 scope link" "0"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
find_IPv6_information
"
assert_output --partial "Unable to find IPv6 ULA/GUA address"
}
@test "IPv6 ULA only: blocking enabled" {
mock_command_2 "$CID" ip \
"-6 address" "inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global" "0"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
find_IPv6_information
"
assert_output --partial "Found IPv6 ULA address"
}
@test "IPv6 GUA only: blocking enabled" {
mock_command_2 "$CID" ip \
"-6 address" "inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global" "0"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
find_IPv6_information
"
assert_output --partial "Found IPv6 GUA address"
}
@test "IPv6 GUA + ULA: ULA takes precedence" {
mock_command_2 "$CID" ip \
"-6 address" "inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global
inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global" "0"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
find_IPv6_information
"
assert_output --partial "Found IPv6 ULA address"
}
@test "IPv6 ULA + GUA: ULA takes precedence" {
mock_command_2 "$CID" ip \
"-6 address" "inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global
inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global" "0"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
find_IPv6_information
"
assert_output --partial "Found IPv6 ULA address"
}
# ---------------------------------------------------------------------------
# IP address validation
# ---------------------------------------------------------------------------
@test "valid_ip accepts and rejects addresses correctly" {
_valid() {
run docker exec "$CID" bash -c "source /opt/pihole/basic-install.sh; valid_ip '${1}'"
assert_success
}
_invalid() {
run docker exec "$CID" bash -c "source /opt/pihole/basic-install.sh; valid_ip '${1}'"
assert_failure
}
_valid "192.168.1.1"
_valid "127.0.0.1"
_valid "255.255.255.255"
_invalid "255.255.255.256"
_invalid "255.255.256.255"
_invalid "255.256.255.255"
_invalid "256.255.255.255"
_invalid "1092.168.1.1"
_invalid "not an IP"
_invalid "8.8.8.8#"
_valid "8.8.8.8#0"
_valid "8.8.8.8#1"
_valid "8.8.8.8#42"
_valid "8.8.8.8#888"
_valid "8.8.8.8#1337"
_valid "8.8.8.8#65535"
_invalid "8.8.8.8#65536"
_invalid "8.8.8.8#-1"
_invalid "00.0.0.0"
_invalid "010.0.0.0"
_invalid "001.0.0.0"
_invalid "0.0.0.0#00"
_invalid "0.0.0.0#01"
_invalid "0.0.0.0#001"
_invalid "0.0.0.0#0001"
_invalid "0.0.0.0#00001"
}

View File

@@ -1,71 +0,0 @@
#!/usr/bin/env bats
# Tests for SELinux handling in basic-install.sh.
# Translated from test_centos_fedora_common_support.py.
# Only runs on rhel family (CentOS/Fedora) — selected by run.sh.
load 'libs/bats-support/load'
load 'libs/bats-assert/load'
load 'helpers/mocks'
TICK="[✓]"
CROSS="[✗]"
CID=""
setup() {
CID=$(docker run -d -t --cap-add=ALL "$IMAGE_TAG")
}
teardown() {
if [[ -n "$CID" ]]; then
docker rm -f "$CID" > /dev/null 2>&1 || true
fi
}
# ---------------------------------------------------------------------------
# Helper: write a mock SELinux config with the given state
# ---------------------------------------------------------------------------
_mock_selinux_config() {
local state="$1" # enforcing, permissive, or disabled
local capitalized
capitalized=$(echo "${state}" | awk '{print toupper(substr($0,1,1)) substr($0,2)}')
mock_command "$CID" getenforce "*" "$capitalized" "0"
docker exec "$CID" bash -c "
mkdir -p /etc/selinux
echo 'SELINUX=${state}' > /etc/selinux/config
"
}
# ---------------------------------------------------------------------------
@test "SELinux enforcing: installer exits with error" {
_mock_selinux_config "enforcing"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
checkSelinux
"
assert_output --partial "${CROSS} Current SELinux: enforcing"
assert_output --partial "SELinux Enforcing detected, exiting installer"
assert_failure
}
@test "SELinux permissive: installer continues" {
_mock_selinux_config "permissive"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
checkSelinux
"
assert_output --partial "${TICK} Current SELinux: permissive"
assert_success
}
@test "SELinux disabled: installer continues" {
_mock_selinux_config "disabled"
run docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
checkSelinux
"
assert_output --partial "${TICK} Current SELinux: disabled"
assert_success
}

View File

@@ -1,60 +0,0 @@
#!/usr/bin/env bats
# Tests for utils.sh — translated from test_any_utils.py
load 'libs/bats-support/load'
load 'libs/bats-assert/load'
CID=""
setup() {
CID=$(docker run -d -t --cap-add=ALL "$IMAGE_TAG")
}
teardown() {
if [[ -n "$CID" ]]; then
docker rm -f "$CID" > /dev/null 2>&1 || true
fi
}
# ---------------------------------------------------------------------------
@test "addOrEditKeyValPair adds and replaces key-value pairs correctly" {
docker exec "$CID" bash -c "
source /opt/pihole/utils.sh
addOrEditKeyValPair './testoutput' 'KEY_ONE' 'value1'
addOrEditKeyValPair './testoutput' 'KEY_TWO' 'value2'
addOrEditKeyValPair './testoutput' 'KEY_ONE' 'value3'
addOrEditKeyValPair './testoutput' 'KEY_FOUR' 'value4'
"
run docker exec "$CID" bash -c "cat ./testoutput"
assert_output "KEY_ONE=value3
KEY_TWO=value2
KEY_FOUR=value4"
}
@test "getFTLPID returns -1 when FTL is not running" {
run docker exec "$CID" bash -c "
source /opt/pihole/utils.sh
getFTLPID
"
assert_output "-1"
}
@test "setFTLConfigValue and getFTLConfigValue round-trip" {
# FTL must be installed for this test
docker exec "$CID" bash -c "
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=\$(get_binary_name)
echo 'development' > /etc/pihole/ftlbranch
binary=\"pihole-FTL\${funcOutput##*pihole-FTL}\"
theRest=\"\${funcOutput%pihole-FTL*}\"
FTLdetect \"\${binary}\" \"\${theRest}\"
"
run docker exec "$CID" bash -c "
source /opt/pihole/utils.sh
setFTLConfigValue 'dns.upstreams' '[\"9.9.9.9\"]' > /dev/null
getFTLConfigValue 'dns.upstreams'
"
assert_output --partial "[ 9.9.9.9 ]"
}

10
test/tox.alpine_3_21.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv:py3]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _alpine_3_21.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py

10
test/tox.alpine_3_22.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv:py3]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _alpine_3_22.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py

10
test/tox.alpine_3_23.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv:py3]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _alpine_3_23.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py

10
test/tox.centos_10.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv:py3]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _centos_10.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py

10
test/tox.centos_9.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv:py3]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _centos_9.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py

10
test/tox.debian_11.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv:py3]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _debian_11.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py

10
test/tox.debian_12.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv:py3]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _debian_12.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py

10
test/tox.debian_13.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv:py3]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _debian_13.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py

10
test/tox.fedora_40.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _fedora_40.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py

10
test/tox.fedora_41.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _fedora_41.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py

10
test/tox.fedora_42.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _fedora_42.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py

10
test/tox.fedora_43.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _fedora_43.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py

10
test/tox.ubuntu_20.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv:py3]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _ubuntu_20.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py

10
test/tox.ubuntu_22.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv:py3]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _ubuntu_22.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py

10
test/tox.ubuntu_24.ini Normal file
View File

@@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv:py3]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _ubuntu_24.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py