Reorganize Firefox configuration and repository documentation
- Configure Firefox with privacy settings and extensions (Bitwarden, Plasma Integration, MetaMask, Kagi Search, uBlock Origin) - Set Kagi as default/only search engine - Add MOZ_USE_XINPUT2=1 for smooth scrolling - Create context/ directory for concise unit documentation - Create tests/ directory for test scripts - Move test-firefox-config.sh to tests/ - Update agents.md with documentation workflow guidelines - Fix syntax errors in desktop.nix and dev.nix
This commit is contained in:
parent
67581adde6
commit
449510c746
10 changed files with 994 additions and 111 deletions
76
tests/README.md
Normal file
76
tests/README.md
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# Tests Directory
|
||||
|
||||
This directory contains test scripts for verifying NixOS configurations.
|
||||
|
||||
## Purpose
|
||||
Automated verification of system configurations to catch issues before deployment.
|
||||
|
||||
## Available Tests
|
||||
|
||||
### Firefox Configuration Test
|
||||
**Script:** `test-firefox-config.sh`
|
||||
|
||||
Verifies Firefox Home Manager configuration for user `jsutter`:
|
||||
- Environment variables (`MOZ_USE_XINPUT2`)
|
||||
- Policy file existence and validity
|
||||
- Extension policies
|
||||
- Profile preferences
|
||||
- Privacy settings
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
./test-firefox-config.sh
|
||||
```
|
||||
|
||||
**Requirements:**
|
||||
- Firefox installed
|
||||
- Valid Home Manager configuration
|
||||
- JSON parsing tool (`jq` or Python)
|
||||
|
||||
## Running Tests
|
||||
|
||||
### All Tests
|
||||
```bash
|
||||
tests/test-firefox-config.sh
|
||||
```
|
||||
|
||||
### Specific Test
|
||||
```bash
|
||||
./tests/test-firefox-config.sh
|
||||
```
|
||||
|
||||
## Test Conventions
|
||||
|
||||
### Shell Scripts
|
||||
- Use `set -e` for error handling
|
||||
- Define colored output for readability
|
||||
- Track pass/fail/skip counts
|
||||
- Return non-zero on failure
|
||||
- Use helper functions (`print_pass`, `print_fail`, etc.)
|
||||
|
||||
### Test Coverage
|
||||
Tests should verify:
|
||||
- Configuration builds successfully
|
||||
- Policies are active (`about:policies`)
|
||||
- Settings are enforced
|
||||
- Extensions are force-installed
|
||||
- User preferences are applied
|
||||
|
||||
## Adding New Tests
|
||||
|
||||
1. Create test script in `tests/`
|
||||
2. Make executable: `chmod +x tests/new-test.sh`
|
||||
3. Document in this README
|
||||
4. Follow naming convention: `test-<service>.sh`
|
||||
|
||||
## Notes
|
||||
|
||||
- Many tests require services to be deployed first
|
||||
- Some Firefox tests require Firefox to have been run once
|
||||
- Automated tests complement manual verification
|
||||
- Update test scripts when configurations change
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- `context/` - Configuration documentation
|
||||
- `agents.md` - Agent procedures
|
||||
477
tests/test-firefox-config.sh
Executable file
477
tests/test-firefox-config.sh
Executable file
|
|
@ -0,0 +1,477 @@
|
|||
#!/usr/bin/env bash
|
||||
# Firefox Configuration Test Script
|
||||
# Tests the Firefox Home Manager configuration for user jsutter
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Test counters
|
||||
PASSED=0
|
||||
FAILED=0
|
||||
SKIPPED=0
|
||||
TOTAL=0
|
||||
|
||||
# Helper functions
|
||||
print_header() {
|
||||
echo ""
|
||||
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
echo -e "${BLUE} $1${NC}"
|
||||
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
}
|
||||
|
||||
print_test() {
|
||||
echo -e "\n${YELLOW}[TEST]${NC} $1"
|
||||
((TOTAL++))
|
||||
}
|
||||
|
||||
print_pass() {
|
||||
echo -e "${GREEN} ✓ PASS${NC}: $1"
|
||||
((PASSED++))
|
||||
}
|
||||
|
||||
print_fail() {
|
||||
echo -e "${RED} ✗ FAIL${NC}: $1"
|
||||
((FAILED++))
|
||||
}
|
||||
|
||||
print_skip() {
|
||||
echo -e "${YELLOW} ⊘ SKIP${NC}: $1"
|
||||
((SKIPPED++))
|
||||
}
|
||||
|
||||
print_info() {
|
||||
echo -e " ℹ ${NC}$1"
|
||||
}
|
||||
|
||||
print_report() {
|
||||
local description="$1"
|
||||
local pass_count="$2"
|
||||
local fail_count="$3"
|
||||
|
||||
if [[ $fail_count -eq 0 ]]; then
|
||||
print_pass "$description (passed $pass_count/$pass_count)"
|
||||
else
|
||||
local total=$((pass_count + fail_count))
|
||||
print_fail "$description (passed $pass_count/$total)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if a command exists
|
||||
command_exists() {
|
||||
command -v "$1" &> /dev/null
|
||||
}
|
||||
|
||||
# Check if a preference matches expected value
|
||||
check_pref() {
|
||||
local profile="$1"
|
||||
local pref="$2"
|
||||
local expected="$3"
|
||||
local actual=$(grep "\"${pref}\"" "$profile/prefs.js" 2>/dev/null | head -1 | sed 's/.*user_pref[^,]*,\s*//;s/);.*$//' 2>/dev/null || echo "")
|
||||
|
||||
if [[ "$actual" == *"$expected"* ]]; then
|
||||
print_pass "$pref = $expected"
|
||||
return 0
|
||||
else
|
||||
print_fail "$pref = $expected (got: $actual)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Get Firefox profile directory
|
||||
get_firefox_profile() {
|
||||
local firefox_dir="$HOME/.mozilla/firefox"
|
||||
|
||||
if [[ -d "$firefox_dir" ]]; then
|
||||
local profile=$(grep -E "Default=1" "$firefox_dir/profiles.ini" 2>/dev/null | head -1 | cut -d= -f2 -s)
|
||||
if [[ -n "$profile" ]] && [[ -d "$firefox_dir/$profile" ]]; then
|
||||
echo "$firefox_dir/$profile"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Try to find jsutter profile
|
||||
profile=$(find "$firefox_dir" -maxdepth 1 -type d -name "*jsutter*" 2>/dev/null | head -1)
|
||||
if [[ -n "$profile" ]]; then
|
||||
echo "$profile"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Get first available profile
|
||||
profile=$(ls -1 "$firefox_dir"/*.default* 2>/dev/null | head -1)
|
||||
if [[ -n "$profile" ]]; then
|
||||
echo "$profile"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
return 1
|
||||
}
|
||||
|
||||
# Get Firefox executable
|
||||
get_firefox_exec() {
|
||||
if command_exists firefox-esr &>/dev/null; then
|
||||
echo firefox-esr
|
||||
elif command_exists firefox &>/dev/null; then
|
||||
echo firefox
|
||||
elif [[ -f "/run/current-system/sw/bin/firefox" ]]; then
|
||||
echo /run/current-system/sw/bin/firefox
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
print_header "Firefox Configuration Test Script"
|
||||
echo "Testing configuration for user: $(whoami)"
|
||||
echo "Date: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
|
||||
# ============================================
|
||||
# Environment Variables
|
||||
# ============================================
|
||||
print_header "1. Environment Variables"
|
||||
|
||||
print_test "Check MOZ_USE_XINPUT2 environment variable"
|
||||
if [[ -z "$MOZ_USE_XINPUT2" ]]; then
|
||||
print_fail "MOZ_USE_XINPUT2 not set"
|
||||
print_info "This should be set in Home Manager sessionVariables"
|
||||
else
|
||||
if [[ "$MOZ_USE_XINPUT2" == "1" ]]; then
|
||||
print_pass "MOZ_USE_XINPUT2 = 1"
|
||||
else
|
||||
print_fail "MOZ_USE_XINPUT2 = $MOZ_USE_XINPUT2 (expected: 1)"
|
||||
fi
|
||||
fi
|
||||
|
||||
print_test "Check session variables in shell config"
|
||||
if [[ -f "$HOME/.zshrc" ]] || [[ -f "$HOME/.bashrc" ]]; then
|
||||
print_info "Shell config files found"
|
||||
else
|
||||
print_skip "No shell config file found"
|
||||
fi
|
||||
|
||||
# ============================================
|
||||
# Firefox Installation
|
||||
# ============================================
|
||||
print_header "2. Firefox Installation"
|
||||
|
||||
FIREFOX=$(get_firefox_exec)
|
||||
if [[ -n "$FIREFOX" ]]; then
|
||||
print_test "Firefox executable found"
|
||||
print_pass "Firefox at: $FIREFOX"
|
||||
|
||||
print_test "Firefox version"
|
||||
VERSION=$($FIREFOX --version 2>/dev/null || echo "unknown")
|
||||
print_pass "Firefox version: $VERSION"
|
||||
else
|
||||
print_fail "Firefox executable not found"
|
||||
print_info "Check if Firefox is installed via nixos-rebuild switch"
|
||||
fi
|
||||
|
||||
# ============================================
|
||||
# Policy Configuration
|
||||
# ============================================
|
||||
print_header "3. Enterprise Policies"
|
||||
|
||||
POLICY_FILE="/run/current-system/sw/lib/firefox/distribution/policies.json"
|
||||
print_test "Check policy file exists"
|
||||
if [[ -f "$POLICY_FILE" ]]; then
|
||||
print_pass "Policy file found: $POLICY_FILE"
|
||||
else
|
||||
print_fail "Policy file not found"
|
||||
print_info "Activate the configuration with: nixos-rebuild switch"
|
||||
fi
|
||||
|
||||
if [[ -f "$POLICY_FILE" ]]; then
|
||||
print_test "Check policy file is valid JSON"
|
||||
if jq empty "$POLICY_FILE" 2>/dev/null; then
|
||||
print_pass "Policy file is valid JSON"
|
||||
else
|
||||
print_fail "Policy file is not valid JSON"
|
||||
fi
|
||||
|
||||
print_test "Check extension policies"
|
||||
EXTENSIONS=$(jq -r '.policies.ExtensionSettings | keys[]' "$POLICY_FILE" 2>/dev/null || echo "")
|
||||
EXPECTED_EXTENSIONS=(
|
||||
"uBlock0@raymondhill.net"
|
||||
"{446900e4-71c2-419f-a6a7-df9c2b2dc922}"
|
||||
"plasma-browser-integration@kde.org"
|
||||
"webextension@metamask.io"
|
||||
"kagi-search@kagi.com"
|
||||
)
|
||||
|
||||
all_found=true
|
||||
for ext in "${EXPECTED_EXTENSIONS[@]}"; do
|
||||
if echo "$EXTENSIONS" | grep -q "$ext"; then
|
||||
print_info "Extension policy found: $ext"
|
||||
else
|
||||
print_fail "Extension policy missing: $ext"
|
||||
all_found=false
|
||||
fi
|
||||
done
|
||||
if $all_found; then
|
||||
print_pass "All extension policies configured"
|
||||
fi
|
||||
|
||||
print_test "Check privacy settings policies"
|
||||
PRIVACY_OK=true
|
||||
|
||||
if jq -e '.policies.OfferToSaveLogins == false' "$POLICY_FILE" &>/dev/null; then
|
||||
print_info "Password saving disabled"
|
||||
else
|
||||
print_fail "Password saving not disabled"
|
||||
PRIVACY_OK=false
|
||||
fi
|
||||
|
||||
if jq -e '.policies.PasswordManagerEnabled == false' "$POLICY_FILE" &>/dev/null; then
|
||||
print_info "Password manager disabled"
|
||||
else
|
||||
print_fail "Password manager not disabled"
|
||||
PRIVACY_OK=false
|
||||
fi
|
||||
|
||||
if jq -e '.policies.DisableTelemetry == true' "$POLICY_FILE" &>/dev/null; then
|
||||
print_info "Telemetry disabled"
|
||||
else
|
||||
print_fail "Telemetry not disabled"
|
||||
PRIVACY_OK=false
|
||||
fi
|
||||
|
||||
if jq -e '.policies.DisableFirefoxStudies == true' "$POLICY_FILE" &>/dev/null; then
|
||||
print_info "Firefox Studies disabled"
|
||||
else
|
||||
print_fail "Firefox Studies not disabled"
|
||||
PRIVACY_OK=false
|
||||
fi
|
||||
|
||||
if $PRIVACY_OK; then
|
||||
print_pass "Privacy settings policies configured correctly"
|
||||
fi
|
||||
|
||||
print_test "Check homepage/new tab policies"
|
||||
HOME_OK=true
|
||||
|
||||
if jq -e '.policies.FirefoxHome.Search == false' "$POLICY_FILE" &>/dev/null; then
|
||||
print_info "Search on home page disabled"
|
||||
else
|
||||
print_fail "Search on home page not disabled"
|
||||
HOME_OK=false
|
||||
fi
|
||||
|
||||
if jq -e '.policies.FirefoxHome.TopSites == false' "$POLICY_FILE" &>/dev/null; then
|
||||
print_info "Top Sites disabled"
|
||||
else
|
||||
print_fail "Top Sites not disabled"
|
||||
HOME_OK=false
|
||||
fi
|
||||
|
||||
if jq -e '.policies.FirefoxHome.Pocket == false' "$POLICY_FILE" &>/dev/null; then
|
||||
print_info "Pocket disabled"
|
||||
else
|
||||
print_fail "Pocket not disabled"
|
||||
HOME_OK=false
|
||||
fi
|
||||
|
||||
if $HOME_OK; then
|
||||
print_pass "Homepage/new tab policies configured correctly"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ============================================
|
||||
# User Profile Configuration
|
||||
# ============================================
|
||||
print_header "4. Profile Configuration"
|
||||
|
||||
PROFILE=$(get_firefox_profile)
|
||||
if [[ -n "$PROFILE" ]]; then
|
||||
print_test "Firefox profile directory found"
|
||||
print_pass "Profile: $PROFILE"
|
||||
|
||||
# Check for user.js
|
||||
USER_JS="$PROFILE/user.js"
|
||||
if [[ -f "$USER_JS" ]]; then
|
||||
print_test "user.js file exists"
|
||||
print_pass "user.js: $USER_JS"
|
||||
|
||||
# Check key settings
|
||||
print_test "Check key user.js preferences"
|
||||
|
||||
cat > /tmp/firefox_check.sh << 'EOF'
|
||||
#!/bin/bash
|
||||
PROFILE="$1"
|
||||
check_pref() {
|
||||
local pref="$1"
|
||||
local expected="$2"
|
||||
local actual=$(grep "\"${pref}\"" "$PROFILE/user.js" 2>/dev/null | head -1 | sed 's/.*user_pref[^,]*,\s*//;s/);.*$//' 2>/dev/null || echo "")
|
||||
|
||||
if [[ "$actual" == *"$expected"* ]]; then
|
||||
echo "PASS: $pref"
|
||||
return 0
|
||||
else
|
||||
echo "FAIL: $pref (got: $actual)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_pref "browser.ctrlTab.recentlyUsedOrder" "true"
|
||||
check_pref "browser.tabs.hoverPreview.enabled" "false"
|
||||
check_pref "browser.link.preview.enabled" "false"
|
||||
check_pref "browser.newtabpage.enabled" "false"
|
||||
check_pref "browser.startup.homepage" "about:blank"
|
||||
check_pref "browser.search.suggest.enabled" "false"
|
||||
check_pref "signon.rememberSignons" "false"
|
||||
check_pref "media.videocontrols.picture-in-picture.allow-multiple" "false"
|
||||
check_pref "browser.contentblocking.category" "strict"
|
||||
check_pref "extensions.pocket.enabled" "false"
|
||||
check_pref "privacy.sanitize.sanitizeOnShutdown" "true"
|
||||
check_pref "toolkit.legacyUserProfileCustomizations.stylesheets" "true"
|
||||
check_pref "privacy.userContext.enabled" "true"
|
||||
EOF
|
||||
chmod +x /tmp/firefox_check.sh
|
||||
output=$(/tmp/firefox_check.sh "$PROFILE")
|
||||
|
||||
pass_count=$(echo "$output" | grep -c "PASS" || true)
|
||||
fail_count=$(echo "$output" | grep -c "FAIL" || true)
|
||||
|
||||
echo "$output" | while read line; do
|
||||
if [[ "$line" == "PASS:"* ]]; then
|
||||
print_pass "${line#PASS: }"
|
||||
else
|
||||
print_fail "${line#FAIL: }"
|
||||
fi
|
||||
done
|
||||
|
||||
print_report "user.js key settings" "$pass_count" "$fail_count"
|
||||
else
|
||||
print_fail "user.js not found (Firefox needs to be run once to generate)"
|
||||
fi
|
||||
|
||||
# Check for extensions
|
||||
print_test "Check installed extensions"
|
||||
INSTALLED_EXTENSIONS=$(ls -1 "$PROFILE/extensions" 2>/dev/null || echo "")
|
||||
|
||||
if [[ -n "$INSTALLED_EXTENSIONS" ]]; then
|
||||
print_info "Found $(echo "$INSTALLED_EXTENSIONS" | wc -l) extension(s):"
|
||||
echo "$INSTALLED_EXTENSIONS" | while read ext; do
|
||||
print_info " - $ext"
|
||||
done
|
||||
print_pass "Extensions directory exists"
|
||||
else
|
||||
print_skip "No extensions installed yet (start Firefox to install via policy)"
|
||||
fi
|
||||
else
|
||||
print_fail "Firefox profile not found"
|
||||
print_info "Start Firefox once to create a profile"
|
||||
print_info "Profile location is typically: ~/.mozilla/firefox/*.default*"
|
||||
fi
|
||||
|
||||
# ============================================
|
||||
# Manual Verification Checklist
|
||||
# ============================================
|
||||
print_header "5. Manual Verification Checklist"
|
||||
|
||||
cat << 'MANUAL'
|
||||
|
||||
The following items require manual verification in Firefox:
|
||||
|
||||
[ ] 1. Open Firefox and check all 4 extensions are installed:
|
||||
- uBlock Origin
|
||||
- Privacy Badger
|
||||
- Facebook Container
|
||||
- Multi-account Containers
|
||||
|
||||
[ ] 2. Open about:preferences#privacy and verify:
|
||||
- Content blocking is set to "Strict"
|
||||
- "Clear history when Firefox closes" is checked
|
||||
- "Remember passwords" is unchecked
|
||||
- "Autoplay" is set to "Block audio and video"
|
||||
|
||||
[ ] 3. Open about:policies and verify:
|
||||
- All policies are "Active"
|
||||
- Extensions are listed as "Force Installed"
|
||||
|
||||
[ ] 4. Test tab behavior:
|
||||
- Press Ctrl+Tab and verify it cycles through recent tabs
|
||||
- Hover over a tab and verify no image preview appears
|
||||
|
||||
[ ] 5. Test new tab/homepage:
|
||||
- Open a new tab (Ctrl+T) - should be blank
|
||||
- Open a new window (Ctrl+N) - should be blank
|
||||
- No search bar, shortcuts, or widgets should appear
|
||||
|
||||
[ ] 6. Test search:
|
||||
- Type in the address bar and verify no suggestions appear
|
||||
- Search results should come from Kagi
|
||||
- No other search engines should be available
|
||||
- Sign in to Kagi account via Kagi extension for full features
|
||||
|
||||
[ ] 7. Test smooth scrolling:
|
||||
- Scroll on a long page - should feel smooth and responsive
|
||||
|
||||
[ ] 8. Test permissions:
|
||||
- Visit a site that requests location - should auto-block
|
||||
- Visit a site that requests notifications - should auto-block
|
||||
- Play a video with audio - should auto-block
|
||||
|
||||
MANUAL
|
||||
|
||||
print_info "Manual verification above requires user interaction"
|
||||
|
||||
# ============================================
|
||||
# Troubleshooting Information
|
||||
# ============================================
|
||||
print_header "6. Troubleshooting Information"
|
||||
|
||||
echo "Useful Firefox URLs:"
|
||||
print_info "about:policies - View active policies"
|
||||
print_info "about:preferences - Firefox settings"
|
||||
print_info "about:config - Advanced preferences"
|
||||
print_info "about:support - Troubleshooting information"
|
||||
print_info "about:addons - View/manage extensions"
|
||||
print_info "about:preferences#privacy - Privacy settings"
|
||||
|
||||
echo ""
|
||||
print_info "Configuration files:"
|
||||
print_info " Policies: $POLICY_FILE"
|
||||
print_info " Profile: $PROFILE"
|
||||
print_info " user.js: $USER_JS"
|
||||
if [[ -n "$PROFILE" ]]; then
|
||||
print_info " search.json.mozlz4: $PROFILE/search.json.mozlz4"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_info "To rebuild the configuration:"
|
||||
print_info " nixos-rebuild switch"
|
||||
|
||||
echo ""
|
||||
print_info "To restart Firefox:"
|
||||
print_info " pkill firefox"
|
||||
|
||||
# ============================================
|
||||
# Summary
|
||||
# ============================================
|
||||
print_header "Test Summary"
|
||||
echo "Total tests: $TOTAL"
|
||||
echo -e "${GREEN}Passed: $PASSED${NC}"
|
||||
echo -e "${RED}Failed: $FAILED${NC}"
|
||||
echo -e "${YELLOW}Skipped: $SKIPPED${NC}"
|
||||
|
||||
if [[ $FAILED -eq 0 ]]; then
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ All automated tests passed!${NC}"
|
||||
echo ""
|
||||
echo "Please run Firefox once to install extensions via policy,"
|
||||
echo "then complete the manual verification checklist above."
|
||||
echo ""
|
||||
echo "Note: Kagi search is the default and only search engine."
|
||||
echo " Sign in to your Kagi account via the Kagi extension."
|
||||
exit 0
|
||||
else
|
||||
echo ""
|
||||
echo -e "${RED}✗ Some tests failed. Review the output above for details.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
Loading…
Add table
Add a link
Reference in a new issue