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
182
agents.md
182
agents.md
|
|
@ -1,9 +1,11 @@
|
||||||
# NixOS Repository Quick Reference
|
# NixOS Repository Agent Instructions
|
||||||
|
|
||||||
|
Instructions for agents working in this repository.
|
||||||
|
|
||||||
## Quick Commands
|
## Quick Commands
|
||||||
- **Test build**: `nixos-rebuild build --flake .#<system>`
|
- Test build: `nixos-rebuild build --flake .#<system>`
|
||||||
- **List systems**: `nix flake show`
|
- List systems: `nix flake show`
|
||||||
- **Commit**: `git add files && git commit -m "msg"`
|
- Commit: `git add files && git commit -m "msg"`
|
||||||
|
|
||||||
## Systems
|
## Systems
|
||||||
- **warp**: Server + nginx + forgejo
|
- **warp**: Server + nginx + forgejo
|
||||||
|
|
@ -15,6 +17,8 @@
|
||||||
- `systems/<name>.nix`: Hardware/boot configs
|
- `systems/<name>.nix`: Hardware/boot configs
|
||||||
- `servers/<name>.nix`: Service configs
|
- `servers/<name>.nix`: Service configs
|
||||||
- `users/<name>.nix`: User configs
|
- `users/<name>.nix`: User configs
|
||||||
|
- `context/`: Documentation for discrete units of work
|
||||||
|
- `tests/`: Test scripts for verification
|
||||||
|
|
||||||
## Testing Workflow
|
## Testing Workflow
|
||||||
1. Always `git status` first - affects flake evaluation
|
1. Always `git status` first - affects flake evaluation
|
||||||
|
|
@ -24,141 +28,111 @@
|
||||||
|
|
||||||
## Important
|
## Important
|
||||||
- Server configs may contain hardcoded credentials
|
- Server configs may contain hardcoded credentials
|
||||||
- Always carefully inspect the NixOS wiki for instructions before adding new applications to the repo
|
- Always carefully inspect the NixOS wiki before adding new applications
|
||||||
- Do not editorialize or pass judgement. Be a robot.
|
- Do not editorialize or pass judgement
|
||||||
- Repository root: `/home/jsutter/src/nixos`
|
- Repository root: `/home/jsutter/src/nixos`
|
||||||
|
|
||||||
## Development Standards
|
## Development Standards
|
||||||
|
|
||||||
### curl Usage
|
### curl Usage
|
||||||
When using curl commands, always set a timeout to 5 seconds:
|
When using curl commands, always set a timeout to 5 seconds:
|
||||||
|
```bash
|
||||||
curl -m 5
|
curl -m 5
|
||||||
|
```
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
Prefer inline comments for self-documenting code. Create concise docs in `context/` for:
|
||||||
|
- Major feature additions
|
||||||
|
- Significant refactoring or restructuring
|
||||||
|
- Cross-service dependencies
|
||||||
|
- Security updates requiring special handling
|
||||||
|
|
||||||
|
See `context/README.md` for detailed guidelines on file naming and content structure.
|
||||||
|
|
||||||
## Procedures
|
## Procedures
|
||||||
|
|
||||||
### Adding a New Application to the Repository
|
### Adding a New Application
|
||||||
|
|
||||||
1. **Gather Requirements**
|
1. **Gather Requirements**
|
||||||
- Ask the user what server to deploy to
|
- Ask user which server to deploy to
|
||||||
- Ask the user what domain name the app will be available on
|
- Ask user for domain name
|
||||||
|
|
||||||
2. **Research and Planning**
|
2. **Research and Planning**
|
||||||
- Build a brief plan to construct the app
|
- Review NixOS wiki for packages/modules
|
||||||
- Review the NixOS wiki (https://nixos.org/nixos/manual/) to see if packages are available
|
- Build brief plan
|
||||||
- Check for existing NixOS modules or services that can be used
|
- Identify dependencies
|
||||||
- Identify dependencies and configuration requirements
|
|
||||||
|
|
||||||
3. **Implementation**
|
3. **Implementation**
|
||||||
- Follow the plan constructed in step 2
|
- Add config to appropriate server file in `servers/`
|
||||||
- Add the necessary configuration to the appropriate server file in `servers/`
|
- Include nginx reverse proxy if needed
|
||||||
- Include nginx reverse proxy configuration if the app needs to be accessible via HTTP/HTTPS
|
- Add firewall rules, services, users
|
||||||
- Add any required firewall rules, services, or users
|
|
||||||
- Create A record at Cloudflare if needed
|
- Create A record at Cloudflare if needed
|
||||||
|
|
||||||
4. **Local Testing**
|
4. **Local Testing**
|
||||||
- Test the build locally: `nixos-rebuild build --flake .#<system>`
|
- `nixos-rebuild build --flake .#<system>`
|
||||||
- Refine the configuration until the build succeeds
|
- Refine until build succeeds
|
||||||
- Review the generated configuration for correctness
|
|
||||||
|
|
||||||
5. **Remote Deployment**
|
5. **Remote Deployment**
|
||||||
- Push the repo to the remote machine: `git push origin master`
|
- `git push origin master`
|
||||||
- SSH to the target server
|
- SSH to target server
|
||||||
- Pull the changes: `cd ~/src/nixos && git pull origin master`
|
- `cd ~/src/nixos && git pull && sudo nixos-rebuild switch --flake .#`
|
||||||
- Build and switch to the new config: `sudo nixos-rebuild switch --flake .#`
|
|
||||||
|
|
||||||
6. **Verification**
|
6. **Verification**
|
||||||
- Ensure the service is available on the chosen domain
|
- Ensure service available on domain
|
||||||
- Ensure the certificate is issued by Let's Encrypt (check with: `openssl s_client -connect <domain>:443 | openssl x509 -noout -issuer`)
|
- Check Let's Encrypt certificate: `openssl s_client -connect <domain>:443 | openssl x509 -noout -issuer`
|
||||||
- Test basic functionality of the application
|
- Test functionality
|
||||||
|
|
||||||
7. **Troubleshooting**
|
7. **Documentation**
|
||||||
- If the app isn't available on the chosen domain:
|
- Create concise doc in `context/` if major feature
|
||||||
- Check service status: `systemctl status <service>`
|
- Add test script to `tests/` if applicable
|
||||||
- Check nginx logs: `journalctl -u nginx -f`
|
|
||||||
- Check application logs: `journalctl -u <service> -f`
|
|
||||||
- Verify DNS resolution
|
|
||||||
- Check firewall rules
|
|
||||||
- Verify nginx configuration syntax: `nginx -t`
|
|
||||||
- If the certificate isn't issued by Let's Encrypt:
|
|
||||||
- Check ACME challenge configuration
|
|
||||||
- Verify domain ownership record
|
|
||||||
- Check Let's Encrypt logs: `journalctl -u certbot -f`
|
|
||||||
- Manually trigger certificate renewal if needed
|
|
||||||
|
|
||||||
### DNS Management
|
### DNS Management
|
||||||
|
|
||||||
#### Create DNS Record via Cloudflare API
|
|
||||||
```bash
|
|
||||||
# Get zone ID for domain
|
|
||||||
ZONE_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=symbiotrip.com" \
|
|
||||||
-H "Authorization: Bearer <CLOUDFLARE_API_TOKEN>" \
|
|
||||||
-H "Content-Type: application/json" | jq -r '.result[0].id')
|
|
||||||
|
|
||||||
# Create A record
|
|
||||||
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
|
|
||||||
-H "Authorization: Bearer <CLOUDFLARE_API_TOKEN>" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
--data '{"type":"A","name":"<subdomain>","content":"<IP_ADDRESS>","ttl":1,"proxied":false}'
|
|
||||||
```
|
|
||||||
**Common DNS Issues:**
|
|
||||||
- Local DNS caching: Add entry to `/etc/hosts` temporarily for testing
|
|
||||||
- Cloudflare proxy can cause SSL/TLS handshake failures - use non-proxied (grey cloud) records for direct server access
|
|
||||||
- Use Cloudflare's proxy IPs directly if DNS propagation is slow
|
|
||||||
|
|
||||||
8. **Process Improvement**
|
|
||||||
- After successful deployment, propose 3 new tools to add to agents.md.
|
|
||||||
|
|
||||||
### Useful Commands
|
|
||||||
|
|
||||||
|
Create A record via Cloudflare API:
|
||||||
```bash
|
```bash
|
||||||
# Check generated configuration before deployment
|
ZONE_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=symbiotrip.com" \
|
||||||
nix eval '.#nixosConfigurations.<system>.config.services.<service>.enable'
|
-H "Authorization: Bearer <TOKEN>" -H "Content-Type: application/json" | jq -r '.result[0].id')
|
||||||
|
|
||||||
# List systemd services from new config
|
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
|
||||||
ls /nix/store/<path>-nixos-system-<system>/etc/systemd/system/*.service
|
-H "Authorization: Bearer <TOKEN>" -H "Content-Type: application/json" \
|
||||||
|
--data '{"type":"A","name":"<subdomain>","content":"<IP>","ttl":1,"proxied":false}'
|
||||||
# Test nginx configuration
|
|
||||||
ssh <hostname> 'nginx -t'
|
|
||||||
|
|
||||||
# Check ACME certificate status
|
|
||||||
ssh <hostname> 'ls -la /var/lib/acme/<domain>/'
|
|
||||||
|
|
||||||
# Verify certificate issuer
|
|
||||||
openssl s_client -connect <domain>:443 | openssl x509 -noout -issuer
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Common Issues:**
|
||||||
|
- Local DNS caching: Add `/etc/hosts` entry for testing
|
||||||
|
- Cloudflare proxy can cause SSL issues - use grey cloud (non-proxied) records
|
||||||
|
|
||||||
## Remote System Management
|
## Remote System Management
|
||||||
|
|
||||||
### Access Systems
|
### Access Systems
|
||||||
SSH to machines using hostnames (resolve via local `/etc/hosts` or DNS):
|
|
||||||
```bash
|
```bash
|
||||||
ssh <hostname> # Replace with actual system name
|
ssh <hostname>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Make Configuration Changes
|
### Make Configuration Changes
|
||||||
1. **Check current systems:** View `flake.nix` for available system configurations
|
```bash
|
||||||
2. **Edit local config:** `cd ~/src/nixos && vim [relevant_file]`
|
# 1. Edit local config
|
||||||
3. **Test build:** `nixos-rebuild build --flake .#<system-name>`
|
cd ~/src/nixos && vim [relevant_file]
|
||||||
4. **Commit and push changes:**
|
|
||||||
```bash
|
# 2. Test build
|
||||||
git add . && git commit -m "description"
|
nixos-rebuild build --flake .#<system>
|
||||||
git push origin master
|
|
||||||
```
|
# 3. Commit and push
|
||||||
5. **Update target systems:**
|
git add . && git commit -m "description" && git push origin master
|
||||||
```bash
|
|
||||||
ssh <hostname> 'cd ~/src/nixos && git pull && sudo nixos-rebuild switch --flake .#'
|
# 4. Deploy to target
|
||||||
```
|
ssh <hostname> 'cd ~/src/nixos && git pull && sudo nixos-rebuild switch --flake .#'
|
||||||
|
```
|
||||||
|
|
||||||
### Bulk Updates
|
### Bulk Updates
|
||||||
```bash
|
```bash
|
||||||
# Update multiple systems
|
|
||||||
for host in host1 host2 host3; do
|
for host in host1 host2 host3; do
|
||||||
ssh $host 'cd ~/src/nixos && git pull && sudo nixos-rebuild switch --flake .#' &
|
ssh $host 'cd ~/src/nixos && git pull && sudo nixos-rebuild switch --flake .#' &
|
||||||
done
|
done
|
||||||
wait # Wait for all updates to complete
|
wait
|
||||||
```
|
```
|
||||||
|
|
||||||
### Quick Management
|
### Useful Commands
|
||||||
```bash
|
```bash
|
||||||
# Check service status
|
# Check service status
|
||||||
ssh <hostname> 'systemctl status <service>'
|
ssh <hostname> 'systemctl status <service>'
|
||||||
|
|
@ -166,18 +140,16 @@ ssh <hostname> 'systemctl status <service>'
|
||||||
# View logs
|
# View logs
|
||||||
ssh <hostname> 'journalctl -u <service> -f'
|
ssh <hostname> 'journalctl -u <service> -f'
|
||||||
|
|
||||||
# Rebuild if build fails
|
# Test nginx config
|
||||||
ssh <hostname> 'cd ~/src/nixos && git pull && sudo nixos-rebuild switch --flake .#'
|
ssh <hostname> 'nginx -t'
|
||||||
|
|
||||||
# Test site availability via IP
|
# Check ACME certs
|
||||||
ssh <hostname> 'curl -k -I https://localhost:<port>'
|
ssh <hostname> 'ls -la /var/lib/acme/<domain>/'
|
||||||
|
|
||||||
|
# Test site availability
|
||||||
curl -I https://<IP> -H "Host: <domain>"
|
curl -I https://<IP> -H "Host: <domain>"
|
||||||
|
|
||||||
# Get public IP
|
|
||||||
curl -s https://api.ipify.org
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Repository
|
## Repository
|
||||||
- **Central:** https://git.symbiotrip.com/jsutter/nixos
|
- **Central**: https://git.symbiotrip.com/jsutter/nixos
|
||||||
- **Config reference:** Check `flake.nix` for system names and module structure
|
- **Update workflow**: Local edit → Push → Remote pull → Rebuild
|
||||||
- **Update workflow:** Local edit → Push → Remote pull → Rebuild
|
|
||||||
73
context/README.md
Normal file
73
context/README.md
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
# Context Directory
|
||||||
|
|
||||||
|
This directory contains concise documentation for discrete units of work performed in this repository.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Document specific configurations, changes, and procedures in a concise format. Prefer clarity over verbosity - use inline comments in code when the config is self-documenting.
|
||||||
|
|
||||||
|
## Organization
|
||||||
|
|
||||||
|
### File Naming
|
||||||
|
- Use lowercase, hyphenated names
|
||||||
|
- Include dates for time-sensitive updates: `feature-update-YYYY-MM-DD.md`
|
||||||
|
- Use descriptive names for ongoing configs: `service-name.md`
|
||||||
|
|
||||||
|
### File Content
|
||||||
|
Each file should document:
|
||||||
|
- **What** changes were made
|
||||||
|
- **Where** the config lives (file paths)
|
||||||
|
- **How** to build/test/deploy
|
||||||
|
- **Why** the change was made (brief context)
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Service Configuration
|
||||||
|
```markdown
|
||||||
|
# Service Name
|
||||||
|
|
||||||
|
**Config:** `servers/service-name.nix`
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Brief description of what this service does.
|
||||||
|
|
||||||
|
## Build & Deploy
|
||||||
|
```bash
|
||||||
|
nixos-rebuild build --flake .#system
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
Key points to remember.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event/Update Documentation
|
||||||
|
```markdown
|
||||||
|
# Feature Update - YYYY-MM-DD
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
- Removed: old-feature
|
||||||
|
- Added: new-feature
|
||||||
|
|
||||||
|
## Resolution
|
||||||
|
How the issue was solved.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
Build commands if relevant.
|
||||||
|
```
|
||||||
|
|
||||||
|
## When to Create Files
|
||||||
|
- Major feature additions to services/desktop configs
|
||||||
|
- Significant refactoring or restructuring
|
||||||
|
- Security updates requiring special handling
|
||||||
|
- Cross-service dependencies
|
||||||
|
- Troubleshooting guides for complex issues
|
||||||
|
|
||||||
|
## When NOT to Create Files
|
||||||
|
- Routine package updates
|
||||||
|
- Self-documenting NixOS configurations
|
||||||
|
- Trivial changes covered by code comments
|
||||||
|
- Temporary debugging (use git commits instead)
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
- `agents.md` - Agent instructions and procedures
|
||||||
|
- `README.md` - Project overview
|
||||||
|
- Test scripts in `tests/`
|
||||||
33
context/firefox-extension-update-2026-02-16.md
Normal file
33
context/firefox-extension-update-2026-02-16.md
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Firefox Extension Update - 2026-02-16
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Privacy Badger (`jid1-MnnxcxisBPnSXQ@jetpack`)
|
||||||
|
- Facebook Container (`@contain-facebook`)
|
||||||
|
- Multi-account Containers (`@testpilot-containers`)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Bitwarden (`{446900e4-71c2-419f-a6a7-df9c2b2dc922}`)
|
||||||
|
- Plasma Integration (`plasma-browser-integration@kde.org`)
|
||||||
|
- MetaMask (`webextension@metamask.io`)
|
||||||
|
- Kagi Search (`kagi-search@kagi.com`)
|
||||||
|
|
||||||
|
### Kept
|
||||||
|
- uBlock Origin (`uBlock0@raymondhill.net`)
|
||||||
|
|
||||||
|
## Search Engine
|
||||||
|
- **Default:** Changed from DuckDuckGo to Kagi
|
||||||
|
- **Alternatives:** All removed (Google, Bing, Yahoo, etc.)
|
||||||
|
|
||||||
|
## Build
|
||||||
|
```bash
|
||||||
|
nixos-rebuild build --flake .#framework
|
||||||
|
sudo nixos-rebuild switch --flake .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Manual Setup
|
||||||
|
Sign in after first launch:
|
||||||
|
- Bitwarden account
|
||||||
|
- MetaMask wallet
|
||||||
|
- Kagi account (for full search features)
|
||||||
52
context/firefox-initial-setup.md
Normal file
52
context/firefox-initial-setup.md
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Firefox Initial Privacy Setup
|
||||||
|
|
||||||
|
**User:** jsutter
|
||||||
|
**Config:** `users/jsutter.nix` → `programs.firefox`
|
||||||
|
|
||||||
|
## Privacy Configuration
|
||||||
|
|
||||||
|
### Privacy Policies (Locked)
|
||||||
|
- Password manager: Disabled
|
||||||
|
- Password saving: Disabled
|
||||||
|
- Form history: Disabled
|
||||||
|
- Telemetry: Disabled
|
||||||
|
- Firefox Studies: Disabled
|
||||||
|
- CaptivePortal: Disabled
|
||||||
|
|
||||||
|
### Homepage & Privacy
|
||||||
|
- Search: Disabled and locked
|
||||||
|
- Top Sites/Highlights/Snippets: Disabled
|
||||||
|
- Recommendations: Disabled (extensions, features)
|
||||||
|
|
||||||
|
### Content Blocking
|
||||||
|
- Mode: Strict
|
||||||
|
- Tracking protection: Enabled (social, fingerprinting, cryptomining)
|
||||||
|
- Do Not Track: Enabled
|
||||||
|
- Fingerprinting resistance: Enabled
|
||||||
|
|
||||||
|
### Permissions (Block All)
|
||||||
|
- Location requests
|
||||||
|
- Notification requests
|
||||||
|
- Autoplay (audio/video)
|
||||||
|
- Virtual Reality requests
|
||||||
|
|
||||||
|
### Data Collection
|
||||||
|
- Sanitize on shutdown: Enabled (cache, cookies, history, etc.)
|
||||||
|
- Private attribution: Disabled
|
||||||
|
- Battery API: Disabled
|
||||||
|
|
||||||
|
## Build & Verify
|
||||||
|
```bash
|
||||||
|
nixos-rebuild build --flake .#framework
|
||||||
|
sudo nixos-rebuild switch --flake .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verification URLs
|
||||||
|
- `about:policies` - Active policies
|
||||||
|
- `about:preferences#privacy` - Privacy settings
|
||||||
|
- `about:preferences#home` - Homepage/new tab settings
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- Original extensions: uBlock Origin, Privacy Badger, Facebook Container, Multi-account Containers
|
||||||
|
- All privacy settings declaratively managed via Home Manager
|
||||||
|
- Settings persist across Firefox updates
|
||||||
45
context/firefox.md
Normal file
45
context/firefox.md
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Firefox Configuration
|
||||||
|
|
||||||
|
**User:** jsutter
|
||||||
|
**Config:** `users/jsutter.nix` → `programs.firefox`
|
||||||
|
|
||||||
|
## Extensions (Force Installed)
|
||||||
|
- **uBlock Origin** - Ad blocker
|
||||||
|
- **Bitwarden** - Password manager
|
||||||
|
- **Plasma Integration** - KDE integration
|
||||||
|
- **MetaMask** - Web3 wallet
|
||||||
|
- **Kagi Search** - Default/only search engine
|
||||||
|
|
||||||
|
## Key Settings
|
||||||
|
- **Search:** Kagi only (all other engines removed)
|
||||||
|
- **Homepage:** Blank page (`about:blank`)
|
||||||
|
- **Privacy:** Strict content blocking, Do Not Track, fingerprinting resistance
|
||||||
|
- **Telemetry:** Disabled
|
||||||
|
- **Permissions:** Block location/notifications/autoplay/VR requests
|
||||||
|
- **Tabs:** Ctrl+Tab cycles in recent order, hover previews disabled
|
||||||
|
- **Performance:** Hardware acceleration enabled, smooth scrolling via `MOZ_USE_XINPUT2=1`
|
||||||
|
|
||||||
|
## Build & Test
|
||||||
|
```bash
|
||||||
|
nixos-rebuild build --flake .#framework
|
||||||
|
./tests/test-firefox-config.sh
|
||||||
|
sudo nixos-rebuild switch --flake .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Manual Setup Required
|
||||||
|
- Sign in to Bitwarden
|
||||||
|
- Sign in to MetaMask
|
||||||
|
- Sign in to Kagi (for full features)
|
||||||
|
- Set zoom per device in `about:config`:
|
||||||
|
- Framework: `layout.css.devPixelsPerPx = 1.1` (110%)
|
||||||
|
- Aurora: `layout.css.devPixelsPerPx = 1.2` (120%)
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
- `about:policies` - Check policies are active
|
||||||
|
- `about:preferences#privacy` - Verify privacy settings
|
||||||
|
- Extensions auto-install on first Firefox launch
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- Extensions cannot be uninstalled (force installed via policy)
|
||||||
|
- Settings are declarative and persist across updates
|
||||||
|
- Title bar hiding requires manual UserChrome.css if desired
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ config, pkgs, pkgs-unstable, lib, octofriend, ... }:
|
{ config, pkgs, pkgs-unstable, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
(python3.withPackages(ps: with ps; [ pandas requests python-dotenv pip uv ]))
|
(python3.withPackages(ps: with ps; [ pandas requests python-dotenv pip uv ]))
|
||||||
nodejs
|
nodejs
|
||||||
putty # SSH/Telnet client
|
putty # SSH/Telnet client
|
||||||
octofriend.packages.${pkgs.system}.default
|
# octofriend.packages.${pkgs.system}.default
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.nix-ld.enable = true;
|
programs.nix-ld.enable = true;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
services.pipewire = {
|
services.pipewire = {
|
||||||
enable = true;
|
enable = true;
|
||||||
alsa.enable = true;
|
alsa.enable = true;
|
||||||
|
|
|
||||||
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
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
home.sessionVariables = {
|
home.sessionVariables = {
|
||||||
OPENAI_API_KEY = "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";
|
OPENAI_API_KEY = "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";
|
||||||
SYNTHETIC_L_API_KEY = "syn_5bfe68ad3826bb7872f32fcf160e959a";
|
SYNTHETIC_L_API_KEY = "syn_5bfe68ad3826bb7872f32fcf160e959a";
|
||||||
|
MOZ_USE_XINPUT2 = "1";
|
||||||
};
|
};
|
||||||
|
|
||||||
programs.git = {
|
programs.git = {
|
||||||
|
|
@ -171,16 +172,77 @@
|
||||||
OfferToSaveLogins = false;
|
OfferToSaveLogins = false;
|
||||||
OfferToSaveLoginsDefault = false;
|
OfferToSaveLoginsDefault = false;
|
||||||
PasswordManagerEnabled = false;
|
PasswordManagerEnabled = false;
|
||||||
|
DisableFormHistory = true;
|
||||||
FirefoxHome = {
|
FirefoxHome = {
|
||||||
Search = true;
|
Search = false;
|
||||||
|
Pocket = false;
|
||||||
|
Snippets = false;
|
||||||
|
TopSites = false;
|
||||||
|
Highlights = false;
|
||||||
|
Locked = {
|
||||||
|
Search = false;
|
||||||
Pocket = false;
|
Pocket = false;
|
||||||
Snippets = false;
|
Snippets = false;
|
||||||
TopSites = false;
|
TopSites = false;
|
||||||
Highlights = false;
|
Highlights = false;
|
||||||
};
|
};
|
||||||
|
};
|
||||||
UserMessaging = {
|
UserMessaging = {
|
||||||
ExtensionRecommendations = false;
|
ExtensionRecommendations = false;
|
||||||
|
FeatureRecommendations = false;
|
||||||
SkipOnboarding = true;
|
SkipOnboarding = true;
|
||||||
|
MoreFromMozilla = false;
|
||||||
|
WhatsNew = false;
|
||||||
|
};
|
||||||
|
FirefoxSuggest = {
|
||||||
|
WebSuggestions = false;
|
||||||
|
SponsoredSuggestions = false;
|
||||||
|
ImprovSuggest = false;
|
||||||
|
Locked = {
|
||||||
|
WebSuggestions = false;
|
||||||
|
SponsoredSuggestions = false;
|
||||||
|
ImprovSuggest = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
Permissions = {
|
||||||
|
Location = {
|
||||||
|
BlockNewRequests = true;
|
||||||
|
Locked = true;
|
||||||
|
};
|
||||||
|
Notifications = {
|
||||||
|
BlockNewRequests = true;
|
||||||
|
Locked = true;
|
||||||
|
};
|
||||||
|
Autoplay = {
|
||||||
|
Default = "block-audio-video";
|
||||||
|
Locked = true;
|
||||||
|
};
|
||||||
|
VirtualReality = {
|
||||||
|
BlockNewRequests = true;
|
||||||
|
Locked = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ExtensionSettings = {
|
||||||
|
"uBlock0@raymondhill.net" = {
|
||||||
|
installation_mode = "force_installed";
|
||||||
|
install_url = "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi";
|
||||||
|
};
|
||||||
|
"{446900e4-71c2-419f-a6a7-df9c2b2dc922}" = {
|
||||||
|
installation_mode = "force_installed";
|
||||||
|
install_url = "https://addons.mozilla.org/firefox/downloads/latest/bitwarden-password-manager/latest.xpi";
|
||||||
|
};
|
||||||
|
"plasma-browser-integration@kde.org" = {
|
||||||
|
installation_mode = "force_installed";
|
||||||
|
install_url = "https://addons.mozilla.org/firefox/downloads/latest/plasma-integration/latest.xpi";
|
||||||
|
};
|
||||||
|
"webextension@metamask.io" = {
|
||||||
|
installation_mode = "force_installed";
|
||||||
|
install_url = "https://addons.mozilla.org/firefox/downloads/latest/ether-metamask/latest.xpi";
|
||||||
|
};
|
||||||
|
"kagi-search@kagi.com" = {
|
||||||
|
installation_mode = "force_installed";
|
||||||
|
install_url = "https://addons.mozilla.org/firefox/downloads/latest/kagi-for-firefox/latest.xpi";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -189,13 +251,106 @@
|
||||||
id = 0;
|
id = 0;
|
||||||
name = "jsutter";
|
name = "jsutter";
|
||||||
settings = {
|
settings = {
|
||||||
"general.smoothScroll" = true;
|
"browser.ctrlTab.recentlyUsedOrder" = true;
|
||||||
|
"browser.urlbar.quicksuggest.enabled" = false;
|
||||||
|
"browser.urlbar.suggest.quicksuggest.sponsored" = false;
|
||||||
|
"browser.urlbar.suggest.quicksuggest.nonsponsored" = false;
|
||||||
|
"browser.link.preview.enabled" = false;
|
||||||
|
"browser.search.suggest.enabled" = false;
|
||||||
|
"browser.search.suggest.enabled.private" = false;
|
||||||
|
"extensions.pocket.enabled" = false;
|
||||||
|
"extensions.pocket.showHome" = false;
|
||||||
|
"browser.contentblocking.category" = "strict";
|
||||||
|
"privacy.sanitize.sanitizeOnShutdown" = true;
|
||||||
|
"privacy.clearOnShutdown.cache" = true;
|
||||||
|
"privacy.clearOnShutdown.cookies" = true;
|
||||||
|
"privacy.clearOnShutdown.downloads" = true;
|
||||||
|
"privacy.clearOnShutdown.formdata" = true;
|
||||||
|
"privacy.clearOnShutdown.history" = true;
|
||||||
|
"privacy.clearOnShutdown.sessions" = true;
|
||||||
|
"signon.rememberSignons" = false;
|
||||||
|
"dom.private-attribution.submission.enabled" = false;
|
||||||
|
"dom.battery.enabled" = false;
|
||||||
|
"browser.uitour.enabled" = false;
|
||||||
|
"browser.urlbar.trimURLs" = true;
|
||||||
|
"layout.css.prefers-color-scheme.content-override" = 0;
|
||||||
|
"browser.tabs.hoverPreview.enabled" = false;
|
||||||
|
"browser.tabs.hoverPreview.showThumbnails" = false;
|
||||||
|
"media.videocontrols.picture-in-picture.allow-multiple" = false;
|
||||||
|
"media.hardware-video-decoding.force-enabled" = true;
|
||||||
|
"widget.gtk.overlay-scrollbars.enabled" = false;
|
||||||
|
"browser.toolbars.bookmarks.visibility" = "newtab";
|
||||||
|
"browser.toolbars.toolbarbuttons.intended.icon-size" = "small";
|
||||||
|
"browser.newtabpage.enabled" = false;
|
||||||
|
"browser.startup.homepage" = "about:blank";
|
||||||
|
"browser.newtabpage.activity-stream.default.sites" = "";
|
||||||
|
"browser.search.region" = "US";
|
||||||
|
"browser.search.isUS" = true;
|
||||||
|
"layers.acceleration.force-enabled" = true;
|
||||||
|
"gfx.webrender.all" = true;
|
||||||
|
"gfx.webrender.enabled" = true;
|
||||||
|
"svg.context-properties.content.enabled" = true;
|
||||||
|
"browser.zoom.full" = true;
|
||||||
|
"ui.key.menuAccessKeyFocuses" = false;
|
||||||
|
};
|
||||||
|
search = {
|
||||||
|
default = "Kagi";
|
||||||
|
engines = {
|
||||||
|
"Kagi" = {
|
||||||
|
urls = [{ template = "https://kagi.com/search?q={searchTerms}"; }];
|
||||||
|
metaData.alias = "@kagi";
|
||||||
|
icon = "https://kagi.com/favicon.ico";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
force = true;
|
||||||
|
privateDefault = "Kagi";
|
||||||
};
|
};
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true);
|
user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true);
|
||||||
user_pref("full-screen-api.ignore-widgets", true);
|
user_pref("full-screen-api.ignore-widgets", true);
|
||||||
user_pref("media.ffmpeg.vaapi.enabled", true);
|
user_pref("media.ffmpeg.vaapi.enabled", true);
|
||||||
user_pref("media.rdd-vpx.enabled", true);
|
user_pref("media.rdd-vpx.enabled", true);
|
||||||
|
user_pref("media.av1.enabled", true);
|
||||||
|
user_pref("media.navigator.video.use_rtt", true);
|
||||||
|
user_pref("browser.display.use_document_fonts", 1);
|
||||||
|
user_pref("browser.display.use_system_colors", false);
|
||||||
|
user_pref("browser.menu.showCharacterEncoding", false);
|
||||||
|
user_pref("browser.newtabpage.activity-stream.feeds.section.topstories.options", "");
|
||||||
|
user_pref("browser.newtabpage.activity-stream.feeds.topsites", false);
|
||||||
|
user_pref("browser.newtabpage.activity-stream.section.highlights.includePocket", false);
|
||||||
|
user_pref("browser.newtabpage.activity-stream.section.highlights.includeVisited", false);
|
||||||
|
user_pref("browser.newtabpage.activity-stream.section.highlights.includeBookmarks", false);
|
||||||
|
user_pref("browser.newtabpage.activity-stream.section.highlights.includeDownloads", false);
|
||||||
|
user_pref("browser.newtabpage.activity-stream.section.highlights.includePocket", false);
|
||||||
|
user_pref("app.shield.optoutstudies.enabled", false);
|
||||||
|
user_pref("datareporting.healthreport.uploadEnabled", false);
|
||||||
|
user_pref("datareporting.policy.dataSubmissionEnabled", false);
|
||||||
|
user_pref("experiments.activeExperiment", false);
|
||||||
|
user_pref("experiments.enabled", false);
|
||||||
|
user_pref("experiments.supported", false);
|
||||||
|
user_pref("network.cookie.cookieBehavior", 1);
|
||||||
|
user_pref("network.dns.disableIPv6", true);
|
||||||
|
user_pref("privacy.donottrackheader.enabled", true);
|
||||||
|
user_pref("privacy.resistFingerprinting", true);
|
||||||
|
user_pref("privacy.trackingprotection.enabled", true);
|
||||||
|
user_pref("privacy.trackingprotection.socialtracking.enabled", true);
|
||||||
|
user_pref("privacy.trackingprotection.fingerprinting.enabled", true);
|
||||||
|
user_pref("privacy.trackingprotection.cryptomining.enabled", true);
|
||||||
|
user_pref("privacy.userContext.enabled", true);
|
||||||
|
user_pref("privacy.userContext.longPressBehavior", 2);
|
||||||
|
user_pref("browser.urlbar.groupLabels.enabled", false);
|
||||||
|
user_pref("browser.search.widget.inNavBar", false);
|
||||||
|
user_pref("browser.search.hiddenOneOffs", "Google,Bing,DuckDuckGo,Amazon,Wikipedia,Yahoo,DDG");
|
||||||
|
user_pref("browser.search.separatePrivateDefault.ui.enabled", false);
|
||||||
|
user_pref("browser.search.suggest.enabled", false);
|
||||||
|
user_pref("browser.search.suggest.enabled.private", false);
|
||||||
|
user_pref("browser.search.order", "");
|
||||||
|
user_pref("browser.search.order.1", "");
|
||||||
|
user_pref("browser.search.order.2", "");
|
||||||
|
user_pref("browser.search.order.3", "");
|
||||||
|
user_pref("browser.search.isUS", true);
|
||||||
|
user_pref("browser.search.region", "US");
|
||||||
|
user_pref("browser.uiCustomization.state", "{\"placements\":{\"widget:[addon]bar-open\",\"nav-bar\":[\"back-button\",\"forward-button\",\"stop-reload-button\",\"urlbar-container\",\"downloads-button\",\"ublock0_raymondhill_net-browser-action\",\"_446900e4-71c2-419f-a6a7-df9c2b2dc922-browser-action\",\"plasma-browser-integration_kde_org-browser-action\",\"webextension_metamask_io-browser-action\",\"kagi-search_kagi_com-browser-action\"],\"toolbar-menubar\":[\"menubar-items\"],\"TabsToolbar\":[\"tabbrowser-tabs\",\"new-tab-button\",\"alltabs-button\"],\"PersonalToolbar\":[\"personal-bookmarks\"]},\"seen\":[\"developer-button\",\"ublock0_raymondhill_net-browser-action\",\"_446900e4-71c2-419f-a6a7-df9c2b2dc922-browser-action\",\"plasma-browser-integration_kde_org-browser-action\",\"webextension_metamask_io-browser-action\",\"kagi-search_kagi_com-browser-action\"],\"dirtyAreaCache\":[\"nav-bar\",\"toolbar-menubar\",\"TabsToolbar\",\"PersonalToolbar\"],\"currentVersion\":18,\"newElementState\":{}}");
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue