db.go:78-95 builds one DSN shared by openScanDatabase (db.go:99) and openReportDatabase (db.go:133), and that DSN includes _pragma=journal_mode(WAL). Setting journal_mode is a write.
README §Database describes the intended deployment as a daily scan cron job maintaining /var/lib/sfdupes/db.sqlite, with report and trees "run interactively whenever needed". In that deployment the database is owned by the cron user (typically root) and the interactive report is not. An unprivileged report therefore fails to open a database it only needs to read. The same failure hits a read-only mount, a ZFS snapshot copy, or a database on read-only media — all natural things to want to run a report against, given the whole design promises analysis never touches the scanned filesystem.
Definition of done
openReportDatabase uses a read-intent DSN: mode=ro plus _pragma=query_only(1), retaining the busy timeout so a report during a concurrent scan still behaves. It must not set journal_mode.
openScanDatabase keeps the read-write DSN unchanged, including WAL.
A test chmods a populated database to 0444 and asserts both report and trees succeed and produce correct output.
README §Database states that report and trees require only read access to the database file.
make check green.
`db.go:78-95` builds one DSN shared by `openScanDatabase` (`db.go:99`) and `openReportDatabase` (`db.go:133`), and that DSN includes `_pragma=journal_mode(WAL)`. Setting `journal_mode` is a write.
README §Database describes the intended deployment as a daily `scan` cron job maintaining `/var/lib/sfdupes/db.sqlite`, with `report` and `trees` "run interactively whenever needed". In that deployment the database is owned by the cron user (typically root) and the interactive report is not. An unprivileged `report` therefore fails to open a database it only needs to read. The same failure hits a read-only mount, a ZFS snapshot copy, or a database on read-only media — all natural things to want to run a report against, given the whole design promises analysis never touches the scanned filesystem.
## Definition of done
1. `openReportDatabase` uses a read-intent DSN: `mode=ro` plus `_pragma=query_only(1)`, retaining the busy timeout so a report during a concurrent scan still behaves. It must not set `journal_mode`.
2. `openScanDatabase` keeps the read-write DSN unchanged, including WAL.
3. A test chmods a populated database to `0444` and asserts both `report` and `trees` succeed and produce correct output.
4. README §Database states that `report` and `trees` require only read access to the database file.
5. `make check` green.
clawbot
added this to the 1.0.0 milestone 2026-08-09 03:44:07 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
db.go:78-95builds one DSN shared byopenScanDatabase(db.go:99) andopenReportDatabase(db.go:133), and that DSN includes_pragma=journal_mode(WAL). Settingjournal_modeis a write.README §Database describes the intended deployment as a daily
scancron job maintaining/var/lib/sfdupes/db.sqlite, withreportandtrees"run interactively whenever needed". In that deployment the database is owned by the cron user (typically root) and the interactive report is not. An unprivilegedreporttherefore fails to open a database it only needs to read. The same failure hits a read-only mount, a ZFS snapshot copy, or a database on read-only media — all natural things to want to run a report against, given the whole design promises analysis never touches the scanned filesystem.Definition of done
openReportDatabaseuses a read-intent DSN:mode=roplus_pragma=query_only(1), retaining the busy timeout so a report during a concurrent scan still behaves. It must not setjournal_mode.openScanDatabasekeeps the read-write DSN unchanged, including WAL.0444and asserts bothreportandtreessucceed and produce correct output.reportandtreesrequire only read access to the database file.make checkgreen.