d92a7399e2
Reserved/private SQL files (sqlpage/ prefix, dotfiles, .. traversal, absolute paths) became directly routable over HTTP while their parsed form was fresh in sql_file_cache. A trusted page loading such a file via sqlpage.run_sql(...) loads it with privilege and caches it; a later direct unprivileged request hit the fresh cache entry before the path guard ran, returning 200 and executing the private SQL instead of 403. The unprivileged path validation is extracted into filesystem::validate_unprivileged_path and now enforced before consulting the cache in both HTTP routing (AppFileStore::contains) and the unprivileged FileCache::get_with_privilege path.