Commit Graph
706 Commits
Author SHA1 Message Date
dependabot[bot] 1c2eb4efec build(deps): bump the gh-actions group with 3 updates (#1552)
[//]: # (dependabot-start)
⚠️  **Dependabot is rebasing this PR** ⚠️ 

Rebasing might not happen immediately, so don't worry if this takes some
time.

Note: if you make any changes to this PR yourself, they will take
precedence over the rebase.

---

[//]: # (dependabot-end)

Bumps the gh-actions group with 3 updates:
[github/codeql-action/init](https://github.com/github/codeql-action),
[github/codeql-action/autobuild](https://github.com/github/codeql-action)
and
[github/codeql-action/analyze](https://github.com/github/codeql-action).

Updates `github/codeql-action/init` from 4.38.3 to 4.39.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/init's
releases</a>.</em></p>
<blockquote>
<h2>v4.39.0</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.20.7. <a
href="https://redirect.github.com/github/codeql-action/pull/4205">#4205</a></li>
<li>The <code>codeql-action/analyze</code> step now validates that a
correct argument for the <code>checkout_path</code> input has been
provided. The <code>checkout_path</code> input must be set to the path
where the repository that is being analyzed is checked out at on the
runner, if that path is something other than the workspace root. If the
path does not point to a repository checkout or is different from the
path that was used by <code>codeql-action/init</code>, then the CodeQL
Action now produces a warning. <a
href="https://redirect.github.com/github/codeql-action/pull/4148">#4148</a></li>
<li>Resolved an issue with third-party caching implementations that
prevented caches from being restored correctly. <a
href="https://redirect.github.com/github/codeql-action/pull/4206">#4206</a></li>
<li>The <code>codeql-action/start-proxy</code> step that is used in Code
Scanning Default Setup now finds CodeQL releases using the same logic as
<code>codeql-action/init</code>. This primarily benefits customers who
are using GitHub instances other than <code>github.com</code> where the
<code>codeql-action/start-proxy</code> step may previously have been
unable to locate recent releases and ended up using outdated versions of
the private registry authentication proxy as a result. <a
href="https://redirect.github.com/github/codeql-action/pull/4198">#4198</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/init's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.39.1 - 21 Oct 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.3">2.27.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4256">#4256</a></li>
</ul>
<h2>4.39.0 - 15 Oct 2026</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.20.7. <a
href="https://redirect.github.com/github/codeql-action/pull/4205">#4205</a></li>
<li>The <code>codeql-action/analyze</code> step now validates that a
correct argument for the <code>checkout_path</code> input has been
provided. The <code>checkout_path</code> input must be set to the path
where the repository that is being analyzed is checked out at on the
runner, if that path is something other than the workspace root. If the
path does not point to a repository checkout or is different from the
path that was used by <code>codeql-action/init</code>, then the CodeQL
Action now produces a warning. <a
href="https://redirect.github.com/github/codeql-action/pull/4148">#4148</a></li>
<li>Resolved an issue with third-party caching implementations that
prevented caches from being restored correctly. <a
href="https://redirect.github.com/github/codeql-action/pull/4206">#4206</a></li>
<li>The <code>codeql-action/start-proxy</code> step that is used in Code
Scanning Default Setup now finds CodeQL releases using the same logic as
<code>codeql-action/init</code>. This primarily benefits customers who
are using GitHub instances other than <code>github.com</code> where the
<code>codeql-action/start-proxy</code> step may previously have been
unable to locate recent releases and ended up using outdated versions of
the private registry authentication proxy as a result. <a
href="https://redirect.github.com/github/codeql-action/pull/4198">#4198</a></li>
</ul>
<h2>4.38.3 - 08 Oct 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: CodeQL version 2.21.2 and earlier
were discontinued on 24 September 2026 alongside GitHub Enterprise
Server 3.17, and will be unsupported by the next minor release of the
CodeQL Action. Added a deprecation warning for customers using these
versions of CodeQL. <a
href="https://redirect.github.com/github/codeql-action/pull/4188">#4188</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.2">2.27.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4203">#4203</a></li>
<li>Fixed a bug where the decision of whether to use a per-language
bundle did not account for custom configurations that reference queries
outside of compiled CodeQL packs. This issue was caught during internal
testing and did not affect any customer repositories. We will resume the
roll out of per-language bundles in the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/4184">#4184</a></li>
</ul>
<h2>4.38.2 - 24 Sept 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.1">2.27.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4160">#4160</a></li>
</ul>
<h2>4.38.1 - 18 Sept 2026</h2>
<ul>
<li>The CodeQL Action now has experimental support for CodeQL releases
for which per-language bundles are available. Per-language bundles
support analysis for a single language and are therefore smaller than
the combined bundles that allow analysis for all supported languages. As
a result, per-language bundles take up less space on disk and are faster
to download. We expect to roll this change out to everyone in the coming
weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/4146">#4146</a></li>
</ul>
<h2>4.38.0 - 09 Sept 2026</h2>
<ul>
<li>On GitHub-hosted runners, the CodeQL Action now deletes unused
CodeQL bundles from the toolcache before downloading a different bundle,
which frees up disk space for the analysis. We expect to roll this
change out to everyone in September. <a
href="https://redirect.github.com/github/codeql-action/pull/4124">#4124</a></li>
<li>The CodeQL Action now supports CodeQL releases that are compatible
with Linux Arm64 and downloads the native <code>linux-arm64</code>
CodeQL bundle when available. <a
href="https://redirect.github.com/github/codeql-action/pull/4072">#4072</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.0">2.27.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4129">#4129</a></li>
</ul>
<h2>4.37.9 - 26 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
<h2>4.37.8 - 21 Aug 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee"><code>6f2ac81</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4239">#4239</a>
from github/update-v4.39.0-d63383a73</li>
<li><a
href="https://github.com/github/codeql-action/commit/eb1c428e6e3725d2b527aec0ee5db4303c8f669d"><code>eb1c428</code></a>
Trigger workflows</li>
<li><a
href="https://github.com/github/codeql-action/commit/444333376e064d207fe1dc74e881528bf11649c1"><code>4443333</code></a>
Update changelog for v4.39.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/d63383a7318b5332e86725adf62ac19528a9786a"><code>d63383a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4233">#4233</a>
from github/mbg/start-proxy/report-version</li>
<li><a
href="https://github.com/github/codeql-action/commit/8dec0b9f88b61a76f5fc97056ee8e7dc8a1a8022"><code>8dec0b9</code></a>
Rename <code>path</code> to <code>result</code> in tests</li>
<li><a
href="https://github.com/github/codeql-action/commit/4eabea6b5e5123ae16fffacf06e86d9d3864c350"><code>4eabea6</code></a>
Merge remote-tracking branch 'origin/main' into
mbg/start-proxy/report-version</li>
<li><a
href="https://github.com/github/codeql-action/commit/57938b85687300731b9b53559017c143d849481d"><code>57938b8</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4201">#4201</a>
from github/mario-campos/automate-changenotes-assemble</li>
<li><a
href="https://github.com/github/codeql-action/commit/ee07b503f465bcf3338b6e4807a36789e3106f4b"><code>ee07b50</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4236">#4236</a>
from github/mbg/add-missing-changenotes</li>
<li><a
href="https://github.com/github/codeql-action/commit/a897ed5c2eeeb4862bf224c65f62a8b2478eb581"><code>a897ed5</code></a>
Add change note for <a
href="https://redirect.github.com/github/codeql-action/issues/4206">#4206</a></li>
<li><a
href="https://github.com/github/codeql-action/commit/c8bd0195fb2ec9584b1bd6faf9ff5e2983c63d82"><code>c8bd019</code></a>
Add change note for <a
href="https://redirect.github.com/github/codeql-action/issues/4198">#4198</a></li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/24c54180a607b1449ed407dd24f251e4e9147c8d...6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/autobuild` from 4.38.3 to 4.39.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/autobuild's
releases</a>.</em></p>
<blockquote>
<h2>v4.39.0</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.20.7. <a
href="https://redirect.github.com/github/codeql-action/pull/4205">#4205</a></li>
<li>The <code>codeql-action/analyze</code> step now validates that a
correct argument for the <code>checkout_path</code> input has been
provided. The <code>checkout_path</code> input must be set to the path
where the repository that is being analyzed is checked out at on the
runner, if that path is something other than the workspace root. If the
path does not point to a repository checkout or is different from the
path that was used by <code>codeql-action/init</code>, then the CodeQL
Action now produces a warning. <a
href="https://redirect.github.com/github/codeql-action/pull/4148">#4148</a></li>
<li>Resolved an issue with third-party caching implementations that
prevented caches from being restored correctly. <a
href="https://redirect.github.com/github/codeql-action/pull/4206">#4206</a></li>
<li>The <code>codeql-action/start-proxy</code> step that is used in Code
Scanning Default Setup now finds CodeQL releases using the same logic as
<code>codeql-action/init</code>. This primarily benefits customers who
are using GitHub instances other than <code>github.com</code> where the
<code>codeql-action/start-proxy</code> step may previously have been
unable to locate recent releases and ended up using outdated versions of
the private registry authentication proxy as a result. <a
href="https://redirect.github.com/github/codeql-action/pull/4198">#4198</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/autobuild's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.39.1 - 21 Oct 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.3">2.27.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4256">#4256</a></li>
</ul>
<h2>4.39.0 - 15 Oct 2026</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.20.7. <a
href="https://redirect.github.com/github/codeql-action/pull/4205">#4205</a></li>
<li>The <code>codeql-action/analyze</code> step now validates that a
correct argument for the <code>checkout_path</code> input has been
provided. The <code>checkout_path</code> input must be set to the path
where the repository that is being analyzed is checked out at on the
runner, if that path is something other than the workspace root. If the
path does not point to a repository checkout or is different from the
path that was used by <code>codeql-action/init</code>, then the CodeQL
Action now produces a warning. <a
href="https://redirect.github.com/github/codeql-action/pull/4148">#4148</a></li>
<li>Resolved an issue with third-party caching implementations that
prevented caches from being restored correctly. <a
href="https://redirect.github.com/github/codeql-action/pull/4206">#4206</a></li>
<li>The <code>codeql-action/start-proxy</code> step that is used in Code
Scanning Default Setup now finds CodeQL releases using the same logic as
<code>codeql-action/init</code>. This primarily benefits customers who
are using GitHub instances other than <code>github.com</code> where the
<code>codeql-action/start-proxy</code> step may previously have been
unable to locate recent releases and ended up using outdated versions of
the private registry authentication proxy as a result. <a
href="https://redirect.github.com/github/codeql-action/pull/4198">#4198</a></li>
</ul>
<h2>4.38.3 - 08 Oct 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: CodeQL version 2.21.2 and earlier
were discontinued on 24 September 2026 alongside GitHub Enterprise
Server 3.17, and will be unsupported by the next minor release of the
CodeQL Action. Added a deprecation warning for customers using these
versions of CodeQL. <a
href="https://redirect.github.com/github/codeql-action/pull/4188">#4188</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.2">2.27.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4203">#4203</a></li>
<li>Fixed a bug where the decision of whether to use a per-language
bundle did not account for custom configurations that reference queries
outside of compiled CodeQL packs. This issue was caught during internal
testing and did not affect any customer repositories. We will resume the
roll out of per-language bundles in the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/4184">#4184</a></li>
</ul>
<h2>4.38.2 - 24 Sept 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.1">2.27.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4160">#4160</a></li>
</ul>
<h2>4.38.1 - 18 Sept 2026</h2>
<ul>
<li>The CodeQL Action now has experimental support for CodeQL releases
for which per-language bundles are available. Per-language bundles
support analysis for a single language and are therefore smaller than
the combined bundles that allow analysis for all supported languages. As
a result, per-language bundles take up less space on disk and are faster
to download. We expect to roll this change out to everyone in the coming
weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/4146">#4146</a></li>
</ul>
<h2>4.38.0 - 09 Sept 2026</h2>
<ul>
<li>On GitHub-hosted runners, the CodeQL Action now deletes unused
CodeQL bundles from the toolcache before downloading a different bundle,
which frees up disk space for the analysis. We expect to roll this
change out to everyone in September. <a
href="https://redirect.github.com/github/codeql-action/pull/4124">#4124</a></li>
<li>The CodeQL Action now supports CodeQL releases that are compatible
with Linux Arm64 and downloads the native <code>linux-arm64</code>
CodeQL bundle when available. <a
href="https://redirect.github.com/github/codeql-action/pull/4072">#4072</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.0">2.27.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4129">#4129</a></li>
</ul>
<h2>4.37.9 - 26 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
<h2>4.37.8 - 21 Aug 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee"><code>6f2ac81</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4239">#4239</a>
from github/update-v4.39.0-d63383a73</li>
<li><a
href="https://github.com/github/codeql-action/commit/eb1c428e6e3725d2b527aec0ee5db4303c8f669d"><code>eb1c428</code></a>
Trigger workflows</li>
<li><a
href="https://github.com/github/codeql-action/commit/444333376e064d207fe1dc74e881528bf11649c1"><code>4443333</code></a>
Update changelog for v4.39.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/d63383a7318b5332e86725adf62ac19528a9786a"><code>d63383a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4233">#4233</a>
from github/mbg/start-proxy/report-version</li>
<li><a
href="https://github.com/github/codeql-action/commit/8dec0b9f88b61a76f5fc97056ee8e7dc8a1a8022"><code>8dec0b9</code></a>
Rename <code>path</code> to <code>result</code> in tests</li>
<li><a
href="https://github.com/github/codeql-action/commit/4eabea6b5e5123ae16fffacf06e86d9d3864c350"><code>4eabea6</code></a>
Merge remote-tracking branch 'origin/main' into
mbg/start-proxy/report-version</li>
<li><a
href="https://github.com/github/codeql-action/commit/57938b85687300731b9b53559017c143d849481d"><code>57938b8</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4201">#4201</a>
from github/mario-campos/automate-changenotes-assemble</li>
<li><a
href="https://github.com/github/codeql-action/commit/ee07b503f465bcf3338b6e4807a36789e3106f4b"><code>ee07b50</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4236">#4236</a>
from github/mbg/add-missing-changenotes</li>
<li><a
href="https://github.com/github/codeql-action/commit/a897ed5c2eeeb4862bf224c65f62a8b2478eb581"><code>a897ed5</code></a>
Add change note for <a
href="https://redirect.github.com/github/codeql-action/issues/4206">#4206</a></li>
<li><a
href="https://github.com/github/codeql-action/commit/c8bd0195fb2ec9584b1bd6faf9ff5e2983c63d82"><code>c8bd019</code></a>
Add change note for <a
href="https://redirect.github.com/github/codeql-action/issues/4198">#4198</a></li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/24c54180a607b1449ed407dd24f251e4e9147c8d...6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/analyze` from 4.38.3 to 4.39.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/analyze's
releases</a>.</em></p>
<blockquote>
<h2>v4.39.0</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.20.7. <a
href="https://redirect.github.com/github/codeql-action/pull/4205">#4205</a></li>
<li>The <code>codeql-action/analyze</code> step now validates that a
correct argument for the <code>checkout_path</code> input has been
provided. The <code>checkout_path</code> input must be set to the path
where the repository that is being analyzed is checked out at on the
runner, if that path is something other than the workspace root. If the
path does not point to a repository checkout or is different from the
path that was used by <code>codeql-action/init</code>, then the CodeQL
Action now produces a warning. <a
href="https://redirect.github.com/github/codeql-action/pull/4148">#4148</a></li>
<li>Resolved an issue with third-party caching implementations that
prevented caches from being restored correctly. <a
href="https://redirect.github.com/github/codeql-action/pull/4206">#4206</a></li>
<li>The <code>codeql-action/start-proxy</code> step that is used in Code
Scanning Default Setup now finds CodeQL releases using the same logic as
<code>codeql-action/init</code>. This primarily benefits customers who
are using GitHub instances other than <code>github.com</code> where the
<code>codeql-action/start-proxy</code> step may previously have been
unable to locate recent releases and ended up using outdated versions of
the private registry authentication proxy as a result. <a
href="https://redirect.github.com/github/codeql-action/pull/4198">#4198</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/analyze's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.39.1 - 21 Oct 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.3">2.27.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4256">#4256</a></li>
</ul>
<h2>4.39.0 - 15 Oct 2026</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.20.7. <a
href="https://redirect.github.com/github/codeql-action/pull/4205">#4205</a></li>
<li>The <code>codeql-action/analyze</code> step now validates that a
correct argument for the <code>checkout_path</code> input has been
provided. The <code>checkout_path</code> input must be set to the path
where the repository that is being analyzed is checked out at on the
runner, if that path is something other than the workspace root. If the
path does not point to a repository checkout or is different from the
path that was used by <code>codeql-action/init</code>, then the CodeQL
Action now produces a warning. <a
href="https://redirect.github.com/github/codeql-action/pull/4148">#4148</a></li>
<li>Resolved an issue with third-party caching implementations that
prevented caches from being restored correctly. <a
href="https://redirect.github.com/github/codeql-action/pull/4206">#4206</a></li>
<li>The <code>codeql-action/start-proxy</code> step that is used in Code
Scanning Default Setup now finds CodeQL releases using the same logic as
<code>codeql-action/init</code>. This primarily benefits customers who
are using GitHub instances other than <code>github.com</code> where the
<code>codeql-action/start-proxy</code> step may previously have been
unable to locate recent releases and ended up using outdated versions of
the private registry authentication proxy as a result. <a
href="https://redirect.github.com/github/codeql-action/pull/4198">#4198</a></li>
</ul>
<h2>4.38.3 - 08 Oct 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: CodeQL version 2.21.2 and earlier
were discontinued on 24 September 2026 alongside GitHub Enterprise
Server 3.17, and will be unsupported by the next minor release of the
CodeQL Action. Added a deprecation warning for customers using these
versions of CodeQL. <a
href="https://redirect.github.com/github/codeql-action/pull/4188">#4188</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.2">2.27.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4203">#4203</a></li>
<li>Fixed a bug where the decision of whether to use a per-language
bundle did not account for custom configurations that reference queries
outside of compiled CodeQL packs. This issue was caught during internal
testing and did not affect any customer repositories. We will resume the
roll out of per-language bundles in the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/4184">#4184</a></li>
</ul>
<h2>4.38.2 - 24 Sept 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.1">2.27.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4160">#4160</a></li>
</ul>
<h2>4.38.1 - 18 Sept 2026</h2>
<ul>
<li>The CodeQL Action now has experimental support for CodeQL releases
for which per-language bundles are available. Per-language bundles
support analysis for a single language and are therefore smaller than
the combined bundles that allow analysis for all supported languages. As
a result, per-language bundles take up less space on disk and are faster
to download. We expect to roll this change out to everyone in the coming
weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/4146">#4146</a></li>
</ul>
<h2>4.38.0 - 09 Sept 2026</h2>
<ul>
<li>On GitHub-hosted runners, the CodeQL Action now deletes unused
CodeQL bundles from the toolcache before downloading a different bundle,
which frees up disk space for the analysis. We expect to roll this
change out to everyone in September. <a
href="https://redirect.github.com/github/codeql-action/pull/4124">#4124</a></li>
<li>The CodeQL Action now supports CodeQL releases that are compatible
with Linux Arm64 and downloads the native <code>linux-arm64</code>
CodeQL bundle when available. <a
href="https://redirect.github.com/github/codeql-action/pull/4072">#4072</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.0">2.27.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4129">#4129</a></li>
</ul>
<h2>4.37.9 - 26 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
<h2>4.37.8 - 21 Aug 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee"><code>6f2ac81</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4239">#4239</a>
from github/update-v4.39.0-d63383a73</li>
<li><a
href="https://github.com/github/codeql-action/commit/eb1c428e6e3725d2b527aec0ee5db4303c8f669d"><code>eb1c428</code></a>
Trigger workflows</li>
<li><a
href="https://github.com/github/codeql-action/commit/444333376e064d207fe1dc74e881528bf11649c1"><code>4443333</code></a>
Update changelog for v4.39.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/d63383a7318b5332e86725adf62ac19528a9786a"><code>d63383a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4233">#4233</a>
from github/mbg/start-proxy/report-version</li>
<li><a
href="https://github.com/github/codeql-action/commit/8dec0b9f88b61a76f5fc97056ee8e7dc8a1a8022"><code>8dec0b9</code></a>
Rename <code>path</code> to <code>result</code> in tests</li>
<li><a
href="https://github.com/github/codeql-action/commit/4eabea6b5e5123ae16fffacf06e86d9d3864c350"><code>4eabea6</code></a>
Merge remote-tracking branch 'origin/main' into
mbg/start-proxy/report-version</li>
<li><a
href="https://github.com/github/codeql-action/commit/57938b85687300731b9b53559017c143d849481d"><code>57938b8</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4201">#4201</a>
from github/mario-campos/automate-changenotes-assemble</li>
<li><a
href="https://github.com/github/codeql-action/commit/ee07b503f465bcf3338b6e4807a36789e3106f4b"><code>ee07b50</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4236">#4236</a>
from github/mbg/add-missing-changenotes</li>
<li><a
href="https://github.com/github/codeql-action/commit/a897ed5c2eeeb4862bf224c65f62a8b2478eb581"><code>a897ed5</code></a>
Add change note for <a
href="https://redirect.github.com/github/codeql-action/issues/4206">#4206</a></li>
<li><a
href="https://github.com/github/codeql-action/commit/c8bd0195fb2ec9584b1bd6faf9ff5e2983c63d82"><code>c8bd019</code></a>
Add change note for <a
href="https://redirect.github.com/github/codeql-action/issues/4198">#4198</a></li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/24c54180a607b1449ed407dd24f251e4e9147c8d...6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 14:39:36 -04:00
dependabot[bot] 3ff6d88681 build(deps): bump astral-sh/uv from 0.12.24 to 0.13.5 in the docker-base-image-digests group (#1550)
> [!WARNING]
> Cooldown could not be applied because no publication date was
available from the registry.
>

Bumps the docker-base-image-digests group with 1 update:
[astral-sh/uv](https://github.com/astral-sh/uv).

Updates `astral-sh/uv` from 0.12.24 to 0.13.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/uv/releases">astral-sh/uv's
releases</a>.</em></p>
<blockquote>
<h2>0.13.5</h2>
<h2>Release Notes</h2>
<p>Released on 2026-10-21.</p>
<p>Following <a
href="https://github.com/astral-sh/uv/releases/tag/0.13.4">uv
0.13.4</a>, which removed the affected eMudhra/emSign root from uv's own
certificate store, this release updates the latest managed CPython
builds for 3.11 and newer to <a
href="https://github.com/astral-sh/python-build-standalone/releases/tag/20261021">python-build-standalone
20261021</a>, including the CPython <a
href="https://www.python.org/downloads/release/python-3151/">3.15.1</a>,
<a
href="https://www.python.org/downloads/release/python-3149/">3.14.9</a>,
and <a
href="https://www.python.org/downloads/release/python-31317/">3.13.17</a>
security patch releases. These builds include <a
href="https://pip.pypa.io/en/stable/news/#v26-2-2">pip 26.2.2</a> both
preinstalled in the managed interpreter and bundled with
<code>ensurepip</code>, which installs pip by default when you run
<code>python -m venv</code>. Both copies use certifi 2026.10.19, which
removes the same affected root. After upgrading uv, run <code>uv python
upgrade</code> to install the updated builds. Virtual environments
pinned to an older Python patch version do not switch to the updated
interpreter automatically. Upgrade pip separately in existing virtual
environments.</p>
<p>Please note upstream CPython 3.9 and 3.10 still bundle pip releases
whose certificate bundles trust the affected eMudhra/emSign root. We
recommend migrating off of those versions and will no longer be
releasing Docker images with uv installed for EOL Python versions.</p>
<h3>Enhancements</h3>
<ul>
<li>Report incompatible self-dependencies directly in resolution errors
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21845">#21845</a>)</li>
</ul>
<h3>Python</h3>
<ul>
<li>Add CPython 3.15.1, 3.14.9, and 3.13.17 (<a
href="https://redirect.github.com/astral-sh/uv/pull/22802">#22802</a>)</li>
</ul>
<h3>Preview features</h3>
<ul>
<li>Select and rank wheel variants with no required properties or
properties from PEP 850 static providers in platform-specific
resolutions with <code>wheel-variants</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/22535">#22535</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/22536">#22536</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/22687">#22687</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/22688">#22688</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Reduce peak memory use when resolving dependencies across multiple
environments (<a
href="https://redirect.github.com/astral-sh/uv/pull/22769">#22769</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/22770">#22770</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/22784">#22784</a>)</li>
<li>Speed up exports with complex transitive extras by resolving
activation across the dependency graph (<a
href="https://redirect.github.com/astral-sh/uv/pull/22751">#22751</a>)</li>
<li>Reduce uv's binary size by keeping additional error formatters out
of line (<a
href="https://redirect.github.com/astral-sh/uv/pull/22775">#22775</a>)</li>
<li>Reduce overhead when parsing custom build cache keys (<a
href="https://redirect.github.com/astral-sh/uv/pull/22749">#22749</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Lock packages distributed only as Android wheels without a source
distribution (<a
href="https://redirect.github.com/astral-sh/uv/pull/22806">#22806</a>)</li>
<li>Export optional dependencies correctly when transitive extras are
activated through different or incompatible environment paths (<a
href="https://redirect.github.com/astral-sh/uv/pull/22751">#22751</a>)</li>
<li>Reject invalid custom build cache keys instead of silently falling
back to the defaults (<a
href="https://redirect.github.com/astral-sh/uv/pull/22749">#22749</a>)</li>
</ul>
<h3>Security</h3>
<ul>
<li>Reject certificate chains containing compromised eMudhra
intermediate keys via <code>rustls-webpki</code> 0.103.16 (<a
href="https://redirect.github.com/astral-sh/uv/pull/22777">#22777</a>)</li>
<li>Stop publishing uv Docker images based on Python 3.9 and 3.10 images
that no longer receive upstream updates (<a
href="https://redirect.github.com/astral-sh/uv/pull/22773">#22773</a>)</li>
</ul>
<h2>Install uv 0.13.5</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/uv/releases/download/0.13.5/uv-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/uv/blob/main/CHANGELOG.md">astral-sh/uv's
changelog</a>.</em></p>
<blockquote>
<h2>0.13.5</h2>
<p>Released on 2026-10-21.</p>
<p>Following <a
href="https://github.com/astral-sh/uv/releases/tag/0.13.4">uv
0.13.4</a>, which removed the affected eMudhra/emSign root from uv's own
certificate store, this release updates the latest managed CPython
builds for 3.11 and newer to <a
href="https://github.com/astral-sh/python-build-standalone/releases/tag/20261021">python-build-standalone
20261021</a>, including the CPython <a
href="https://www.python.org/downloads/release/python-3151/">3.15.1</a>,
<a
href="https://www.python.org/downloads/release/python-3149/">3.14.9</a>,
and <a
href="https://www.python.org/downloads/release/python-31317/">3.13.17</a>
security patch releases. These builds include <a
href="https://pip.pypa.io/en/stable/news/#v26-2-2">pip 26.2.2</a> both
preinstalled in the managed interpreter and bundled with
<code>ensurepip</code>, which installs pip by default when you run
<code>python -m venv</code>. Both copies use certifi 2026.10.19, which
removes the same affected root. After upgrading uv, run <code>uv python
upgrade</code> to install the updated builds. Virtual environments
pinned to an older Python patch version do not switch to the updated
interpreter automatically. Upgrade pip separately in existing virtual
environments.</p>
<p>Please note upstream CPython 3.9 and 3.10 still bundle pip releases
whose certificate bundles trust the affected eMudhra/emSign root. We
recommend migrating off of those versions and will no longer be
releasing Docker images with uv installed for EOL Python versions.</p>
<h3>Enhancements</h3>
<ul>
<li>Report incompatible self-dependencies directly in resolution errors
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21845">#21845</a>)</li>
</ul>
<h3>Python</h3>
<ul>
<li>Add CPython 3.15.1, 3.14.9, and 3.13.17 (<a
href="https://redirect.github.com/astral-sh/uv/pull/22802">#22802</a>)</li>
</ul>
<h3>Preview features</h3>
<ul>
<li>Select and rank wheel variants with no required properties or
properties from PEP 850 static providers in platform-specific
resolutions with <code>wheel-variants</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/22535">#22535</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/22536">#22536</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/22687">#22687</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/22688">#22688</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Reduce peak memory use when resolving dependencies across multiple
environments (<a
href="https://redirect.github.com/astral-sh/uv/pull/22769">#22769</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/22770">#22770</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/22784">#22784</a>)</li>
<li>Speed up exports with complex transitive extras by resolving
activation across the dependency graph (<a
href="https://redirect.github.com/astral-sh/uv/pull/22751">#22751</a>)</li>
<li>Reduce uv's binary size by keeping additional error formatters out
of line (<a
href="https://redirect.github.com/astral-sh/uv/pull/22775">#22775</a>)</li>
<li>Reduce overhead when parsing custom build cache keys (<a
href="https://redirect.github.com/astral-sh/uv/pull/22749">#22749</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Lock packages distributed only as Android wheels without a source
distribution (<a
href="https://redirect.github.com/astral-sh/uv/pull/22806">#22806</a>)</li>
<li>Export optional dependencies correctly when transitive extras are
activated through different or incompatible environment paths (<a
href="https://redirect.github.com/astral-sh/uv/pull/22751">#22751</a>)</li>
<li>Reject invalid custom build cache keys instead of silently falling
back to the defaults (<a
href="https://redirect.github.com/astral-sh/uv/pull/22749">#22749</a>)</li>
</ul>
<h3>Security</h3>
<ul>
<li>Reject certificate chains containing compromised eMudhra
intermediate keys via <code>rustls-webpki</code> 0.103.16 (<a
href="https://redirect.github.com/astral-sh/uv/pull/22777">#22777</a>)</li>
<li>Stop publishing uv Docker images based on Python 3.9 and 3.10 images
that no longer receive upstream updates (<a
href="https://redirect.github.com/astral-sh/uv/pull/22773">#22773</a>)</li>
</ul>
<h2>0.13.4</h2>
<p>Released on 2026-10-20.</p>
<h3>Preview features</h3>
<ul>
<li>Validate PEP 825 variant metadata and treat package versions with
invalid metadata as unavailable under <code>wheel-variants</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/22512">#22512</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Update the bundled Mozilla root certificates via
<code>webpki-root-certs</code> 1.0.10 (<a
href="https://redirect.github.com/astral-sh/uv/pull/22760">#22760</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/uv/commit/46776a95d6686ac0160c10611327ce491e6b202f"><code>46776a9</code></a>
Use checked-in Python metadata for trampoline checks (<a
href="https://redirect.github.com/astral-sh/uv/issues/22811">#22811</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/5babfa90b420ea12a611554f8cbbb41d433534be"><code>5babfa9</code></a>
Use checked-in Python download metadata for releases (<a
href="https://redirect.github.com/astral-sh/uv/issues/22810">#22810</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/06fbc976b1462d56bc83609e1c26250740e9c656"><code>06fbc97</code></a>
Reject Cargo.lock changes from forks (<a
href="https://redirect.github.com/astral-sh/uv/issues/22381">#22381</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/b3c01fd5745ab459863b83380dbd79621073a797"><code>b3c01fd</code></a>
Prepare 0.13.5 (<a
href="https://redirect.github.com/astral-sh/uv/issues/22809">#22809</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/a02d446bcddd8a00c98084709b6bdccbc9a8208f"><code>a02d446</code></a>
Update to include Python 3.15.1, 3.14.9, 3.13.17 (<a
href="https://redirect.github.com/astral-sh/uv/issues/22802">#22802</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/0ee565f1d755dfa5d7ba78db287ed342ec3e4d4b"><code>0ee565f</code></a>
Reproduce local-version marker rendering panic (<a
href="https://redirect.github.com/astral-sh/uv/issues/22807">#22807</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/e3810e1e6daf06095ac58a27dd422eb095ea4ed6"><code>e3810e1</code></a>
Infer platform markers from Android wheel tags (<a
href="https://redirect.github.com/astral-sh/uv/issues/22806">#22806</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/75698b1ed23dd410421de4656304077351641fa7"><code>75698b1</code></a>
Update rustup in Docker builders (<a
href="https://redirect.github.com/astral-sh/uv/issues/22803">#22803</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/1765e51d67f43299d8fbd37b302b773a80c8499d"><code>1765e51</code></a>
Replace actions/attest-build-provenance action with actions/attest
v4.2.2 (<a
href="https://redirect.github.com/astral-sh/uv/issues/2">#2</a>...</li>
<li><a
href="https://github.com/astral-sh/uv/commit/0abe802a1a07417f5163e57549c93c132cd7db3f"><code>0abe802</code></a>
Update Rust crate test-log to v0.2.21 (<a
href="https://redirect.github.com/astral-sh/uv/issues/19721">#19721</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/uv/compare/0.12.24...0.13.5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=astral-sh/uv&package-manager=docker&previous-version=0.12.24&new-version=0.13.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 14:39:23 -04:00
dependabot[bot] eb84426890 build(deps): bump werkzeug from 3.1.8 to 3.1.9 (#1553)
Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.1.8 to
3.1.9.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pallets/werkzeug/releases">werkzeug's
releases</a>.</em></p>
<blockquote>
<h2>3.1.9</h2>
<p>This is the Werkzeug 3.1.9 security fix release, which fixes security
issues and bugs but does not otherwise change behavior and should not
result in breaking changes compared to the latest feature release.</p>
<p>PyPI: <a
href="https://pypi.org/project/Werkzeug/3.1.9/">https://pypi.org/project/Werkzeug/3.1.9/</a>
Changes: <a
href="https://werkzeug.palletsprojects.com/page/changes/#version-3-1-9">https://werkzeug.palletsprojects.com/page/changes/#version-3-1-9</a>
Milestone: <a
href="https://github.com/pallets/werkzeug/milestone/46?closed=1">https://github.com/pallets/werkzeug/milestone/46?closed=1</a></p>
<ul>
<li><code>safe_join</code> on Windows does not allow special devices
names with empty ADS markers on NTFS. <a
href="https://github.com/pallets/werkzeug/security/advisories/GHSA-g6x2-hccm-hh4m">https://github.com/pallets/werkzeug/security/advisories/GHSA-g6x2-hccm-hh4m</a></li>
<li><code>ProfilerMiddleware</code> uses <code>profiling.tracing</code>
on Python 3.15. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3207">#3207</a></li>
<li><code>uri_to_iri</code> and <code>iri_to_uri</code> preserve empty
username, password, and port 0. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3189">#3189</a></li>
<li>Improve performance of <code>parse_options_header</code>. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3231">#3231</a></li>
<li>Improve performance of <code>parse_etags</code>. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3231">#3231</a></li>
<li>Improve performance of <code>parse_cookie</code>. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3231">#3231</a></li>
<li><code>get_host</code> also checks that the port is in the valid
range. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3236">#3236</a></li>
<li>The <code>int</code> URL converter returns a 404 instead of 500
error when the value is longer than
<code>sys.get_int_max_str_digits()</code>. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3237">#3237</a></li>
<li>Improve debugger PIN generation from cgroup data inside Podman. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3245">#3245</a></li>
<li><code>Authorization</code> parsing <code>basic</code> auth disallows
non-base64 characters. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3248">#3248</a></li>
<li><code>application/x-www-form-urlencoded</code> form data is no
longer limited to <code>max_form_memory_size</code>, only
<code>max_content_length</code>. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3251">#3251</a></li>
<li><code>LimitedStream.readinto</code> does not resize the buffer when
it reads less than the remaining size. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3253">#3253</a></li>
<li>Rules with 10 or more converters in a single part assign matched
values correctly. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3254">#3254</a></li>
<li>The invalid <code>Range</code> suffix length <code>-0</code> is no
longer accepted. <a
href="https://redirect.github.com/pallets/werkzeug/issues/3255">#3255</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pallets/werkzeug/blob/main/CHANGES.rst">werkzeug's
changelog</a>.</em></p>
<blockquote>
<h2>Version 3.1.9</h2>
<p>Released 2026-09-27</p>
<ul>
<li><code>safe_join</code> on Windows does not allow special devices
names with empty ADS
markers on NTFS. :ghsa:<code>g6x2-hccm-hh4m</code></li>
<li><code>ProfilerMiddleware</code> uses <code>profiling.tracing</code>
on Python 3.15.
:issue:<code>3207</code></li>
<li><code>uri_to_iri</code> and <code>iri_to_uri</code> preserve empty
username, password, and
port 0. :issue:<code>3189</code></li>
<li>Improve performance of <code>parse_options_header</code>.
:pr:<code>3231</code></li>
<li>Improve performance of <code>parse_etags</code>.
:pr:<code>3231</code></li>
<li>Improve performance of <code>parse_cookie</code>.
:pr:<code>3231</code></li>
<li><code>get_host</code> also checks that the port is in the valid
range. :pr:<code>3236</code></li>
<li>The <code>int</code> URL converter returns a 404 instead of 500
error when the value
is longer than <code>sys.get_int_max_str_digits()</code>.
:issue:<code>3237</code></li>
<li>Improve debugger PIN generation from cgroup data inside Podman.
:issue:<code>3245</code></li>
<li><code>Authorization</code> parsing <code>basic</code> auth disallows
non-base64 characters.
:pr:<code>3248</code></li>
<li><code>application/x-www-form-urlencoded</code> form data is no
longer limited to
<code>max_form_memory_size</code>, only <code>max_content_length</code>.
:pr:<code>3251</code></li>
<li><code>LimitedStream.readinto</code> does not resize the buffer when
it reads less
than the remaining size. :pr:<code>3253</code></li>
<li>Rules with 10 or more converters in a single part assign matched
values
correctly. :pr:<code>3254</code></li>
<li>The invalid <code>Range</code> suffix length <code>-0</code> is no
longer accepted. :pr:<code>3255</code></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/pallets/werkzeug/commit/6604c3b8784ecc7cf5ac0b7412d916989b4c7d45"><code>6604c3b</code></a>
release version 3.1.9</li>
<li><a
href="https://github.com/pallets/werkzeug/commit/a78b30ac0cafe53a4f252ffbf827bf6da7591341"><code>a78b30a</code></a>
update dependencies</li>
<li><a
href="https://github.com/pallets/werkzeug/commit/8d77320bcdf3a34941ec06dcf16b03c065cd21b6"><code>8d77320</code></a>
disallow special name with ads (<a
href="https://redirect.github.com/pallets/werkzeug/issues/3309">#3309</a>)</li>
<li><a
href="https://github.com/pallets/werkzeug/commit/b2a2c09730086ab2d375f0b069c821d4edf526b7"><code>b2a2c09</code></a>
disallow special name with ads</li>
<li><a
href="https://github.com/pallets/werkzeug/commit/4efac9df7ebabe13f82ab0823d5ca0109db20bc3"><code>4efac9d</code></a>
add links</li>
<li><a
href="https://github.com/pallets/werkzeug/commit/400c23e01953311bb0959586f7194191732b18bc"><code>400c23e</code></a>
Allow flit_core 4.x (<a
href="https://redirect.github.com/pallets/werkzeug/issues/3261">#3261</a>)</li>
<li><a
href="https://github.com/pallets/werkzeug/commit/7132a19c26320ae01076d2743df42b9913bbe1d7"><code>7132a19</code></a>
allow flit_core 4</li>
<li><a
href="https://github.com/pallets/werkzeug/commit/6fba87c311e55b4afcef71393a1733498b16676f"><code>6fba87c</code></a>
only accept ASCII digits</li>
<li><a
href="https://github.com/pallets/werkzeug/commit/263f5caf2e26ebd85e38f899628c22f6813c7a2f"><code>263f5ca</code></a>
disallow range -0 (<a
href="https://redirect.github.com/pallets/werkzeug/issues/3255">#3255</a>)</li>
<li><a
href="https://github.com/pallets/werkzeug/commit/0c419f951f3206c89e7c95155f0bd771b02a961f"><code>0c419f9</code></a>
disallow range -0</li>
<li>Additional commits viewable in <a
href="https://github.com/pallets/werkzeug/compare/3.1.8...3.1.9">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=werkzeug&package-manager=uv&previous-version=3.1.8&new-version=3.1.9)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/calibrain/shelfmark/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 14:38:57 -04:00
splitsec2 67a969d953 ci(codeql): skip the tests directory (#1557)
CodeQL scans `tests/`, which only runs in CI and the e2e docker stack.
That is where the open `py/full-ssrf` (critical) and the two
`py/reflective-xss` alerts come from, all in the e2e mock server, plus
four `py/incomplete-url-substring-sanitization` alerts on URL asserts.
None of them can reach a running instance.

This adds `.github/codeql/codeql-config.yml` with `paths-ignore: tests`
and points the init step at it. It closes those seven and hides nothing
in `shelfmark/` or the frontend. The rest of the open alerts are
unchanged.

@calibrain I know I have ability to merge this, but wanted you to be the
one for this. It clears the test alerts and leaves the rest, and
prevents you from having to clear them manually. Just a little QoL.
2026-10-23 14:35:31 -04:00
dependabot[bot] 193351c5a0 build(deps): bump certifi from 2026.7.22 to 2026.10.19 (#1554)
Bumps [certifi](https://github.com/certifi/python-certifi) from
2026.7.22 to 2026.10.19.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/certifi/python-certifi/commit/662df63d7906df66f1f07c0751a3dfe9da14d914"><code>662df63</code></a>
Restore unaffected emSign roots (<a
href="https://redirect.github.com/certifi/python-certifi/issues/439">#439</a>)
(<a
href="https://redirect.github.com/certifi/python-certifi/issues/440">#440</a>)</li>
<li><a
href="https://github.com/certifi/python-certifi/commit/5cb238caeeb6c30ec1a7309ad3e16a5aa7b10ce8"><code>5cb238c</code></a>
Remove emsign (<a
href="https://redirect.github.com/certifi/python-certifi/issues/437">#437</a>)</li>
<li><a
href="https://github.com/certifi/python-certifi/commit/69494a764d0a08f90838d53d4b0fefd3e84045d6"><code>69494a7</code></a>
Bump actions/download-artifact from 8.0.1 to 8.0.2 (<a
href="https://redirect.github.com/certifi/python-certifi/issues/436">#436</a>)</li>
<li><a
href="https://github.com/certifi/python-certifi/commit/029c7b0913d79e2efb73a216fc5c5e13ef958536"><code>029c7b0</code></a>
Bump actions/upload-artifact from 7.0.1 to 7.0.2 (<a
href="https://redirect.github.com/certifi/python-certifi/issues/435">#435</a>)</li>
<li><a
href="https://github.com/certifi/python-certifi/commit/9d0a8f1f3a0d6b2e38d5773db7afe1a37e4527b6"><code>9d0a8f1</code></a>
Add support for Python 3.15 (<a
href="https://redirect.github.com/certifi/python-certifi/issues/432">#432</a>)</li>
<li><a
href="https://github.com/certifi/python-certifi/commit/db472abf0a37067cb4488f036f4c19adf6b6ec3c"><code>db472ab</code></a>
Bump pypa/gh-action-pypi-publish from 1.14.1 to 1.14.2 (<a
href="https://redirect.github.com/certifi/python-certifi/issues/431">#431</a>)</li>
<li>See full diff in <a
href="https://github.com/certifi/python-certifi/compare/2026.07.22...2026.10.19">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=certifi&package-manager=uv&previous-version=2026.7.22&new-version=2026.10.19)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/calibrain/shelfmark/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 02:02:35 -06:00
splitsec2 e33803cac2 build(deps): update socket.io-parser, ws and baseline-browser-mapping in the lockfiles (#1560)
Dependabot has four open npm alerts and no PRs for them, since they are
all transitive. This updates the lockfiles only, no package.json change.

| Package | From | To | Alert |
|---|---|---|---|
| socket.io-parser | 4.2.6 | 4.2.7 | zero-attachment memory exhaustion
(high) |
| ws | 8.18.3 | 8.21.3 | memory exhaustion DoS (high) and uninitialized
memory disclosure (medium) |
| engine.io-client | 6.6.4 | 6.6.7 | needed to get ws past its `~8.18`
range |
| baseline-browser-mapping | 2.9.19 | 2.11.31 | process termination on
invalid input (medium, dev only) |

I think the practical risk was low to begin with, since ws is only used
by engine.io-client under Node and the built bundle doesn't include it.
Still, it clears the alerts and the bumps are small.

Done with npm 11 so the `libc` fields in the lockfile stay as they were.
A clean `npm ci` from the new lockfile gives 0 vulnerabilities, and
`tsc`, `vitest` (241 tests) and `vite build` all pass.
2026-10-23 02:00:44 -06:00
dependabot[bot] 00c03e3058 build(deps): bump oauthlib from 3.3.1 to 4.0.0 (#1556)
Bumps [oauthlib](https://github.com/oauthlib/oauthlib) from 3.3.1 to
4.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oauthlib/oauthlib/releases">oauthlib's
releases</a>.</em></p>
<blockquote>
<h2>4.0.0</h2>
<h2>Introduction</h2>
<p>The release 4.0.0 defines the foundation that enables AI
contributions and will improve the maintenance of oauthlib by using AI
agents, skills, code for both contributors and maintainers. It includes
devcontainer, skills and cleanup of instructions.</p>
<h2>What's Changed</h2>
<p><strong>Important</strong>: this release contains 2 breaking changes.
See CHANGELOG.rst for details:</p>
<ul>
<li>Removed JSONP support from token revocation endpoint (<a
href="https://redirect.github.com/oauthlib/oauthlib/issues/951">#951</a>)</li>
<li>Client authentication validation reorganized across grants (<a
href="https://redirect.github.com/oauthlib/oauthlib/issues/919">#919</a>,
<a
href="https://redirect.github.com/oauthlib/oauthlib/issues/920">#920</a>):
the <code>grant_type</code> parameter is now validated before client
authentication.</li>
</ul>
<ul>
<li>Replace pyenv with uv in documentation and tooling by <a
href="https://github.com/JonathanHuot"><code>@​JonathanHuot</code></a>
in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/910">oauthlib/oauthlib#910</a></li>
<li>Improve github action to publish package by <a
href="https://github.com/JonathanHuot"><code>@​JonathanHuot</code></a>
in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/915">oauthlib/oauthlib#915</a></li>
<li>Add pre-commit to run linters, formatters, etc. on code changes by
<a href="https://github.com/cclauss"><code>@​cclauss</code></a> in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/918">oauthlib/oauthlib#918</a></li>
<li>Fix client authentication for DeviceCodeGrant when getting a token
by <a href="https://github.com/hekhuisk"><code>@​hekhuisk</code></a> in
<a
href="https://redirect.github.com/oauthlib/oauthlib/pull/920">oauthlib/oauthlib#920</a></li>
<li>Add project URLs to this project's PyPI page by <a
href="https://github.com/Flimm"><code>@​Flimm</code></a> in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/921">oauthlib/oauthlib#921</a></li>
<li>Fix a typo in ServiceApplicationClient docstring. by <a
href="https://github.com/rafalkrupinski"><code>@​rafalkrupinski</code></a>
in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/923">oauthlib/oauthlib#923</a></li>
<li>Correct grammar in function help by <a
href="https://github.com/verhovsky"><code>@​verhovsky</code></a> in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/924">oauthlib/oauthlib#924</a></li>
<li>Add Python 3.14 to the testing by <a
href="https://github.com/cclauss"><code>@​cclauss</code></a> in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/925">oauthlib/oauthlib#925</a></li>
<li>Initial python/uv/tox devcontainer by <a
href="https://github.com/JonathanHuot"><code>@​JonathanHuot</code></a>
in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/930">oauthlib/oauthlib#930</a></li>
<li>Fix ruff checks about unused variables by <a
href="https://github.com/JonathanHuot"><code>@​JonathanHuot</code></a>
in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/931">oauthlib/oauthlib#931</a></li>
<li>Drop EOL Python 3.8 from CI by <a
href="https://github.com/auvipy"><code>@​auvipy</code></a> in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/932">oauthlib/oauthlib#932</a></li>
<li>Set Open Collective username to 'oauthlib' by <a
href="https://github.com/auvipy"><code>@​auvipy</code></a> in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/933">oauthlib/oauthlib#933</a></li>
<li>pre-commit autoupdate 2026_02_21 by <a
href="https://github.com/cclauss"><code>@​cclauss</code></a> in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/934">oauthlib/oauthlib#934</a></li>
<li>Remove a trailing whitespace fo fix failing pre-commit by <a
href="https://github.com/cclauss"><code>@​cclauss</code></a> in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/935">oauthlib/oauthlib#935</a></li>
<li>Fix typos discovered by typos by <a
href="https://github.com/cclauss"><code>@​cclauss</code></a> in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/938">oauthlib/oauthlib#938</a></li>
<li>Add <code>resource</code> to Request._params by <a
href="https://github.com/juannyG"><code>@​juannyG</code></a> in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/942">oauthlib/oauthlib#942</a></li>
<li>Release 3.4.0: Add OAuthLib Maintainer agent by <a
href="https://github.com/JonathanHuot"><code>@​JonathanHuot</code></a>
in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/950">oauthlib/oauthlib#950</a></li>
<li>Remove JSONP support from token revocation by <a
href="https://github.com/JonathanHuot"><code>@​JonathanHuot</code></a>
in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/951">oauthlib/oauthlib#951</a></li>
<li>Improve PKCE code comparison by <a
href="https://github.com/JonathanHuot"><code>@​JonathanHuot</code></a>
in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/963">oauthlib/oauthlib#963</a></li>
<li>Release 4.0.0: bump and update changelog by <a
href="https://github.com/JonathanHuot"><code>@​JonathanHuot</code></a>
in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/976">oauthlib/oauthlib#976</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/hekhuisk"><code>@​hekhuisk</code></a>
made their first contribution in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/920">oauthlib/oauthlib#920</a></li>
<li><a href="https://github.com/Flimm"><code>@​Flimm</code></a> made
their first contribution in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/921">oauthlib/oauthlib#921</a></li>
<li><a href="https://github.com/verhovsky"><code>@​verhovsky</code></a>
made their first contribution in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/924">oauthlib/oauthlib#924</a></li>
<li><a href="https://github.com/juannyG"><code>@​juannyG</code></a> made
their first contribution in <a
href="https://redirect.github.com/oauthlib/oauthlib/pull/942">oauthlib/oauthlib#942</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/oauthlib/oauthlib/compare/v3.3.1...v4.0.0">https://github.com/oauthlib/oauthlib/compare/v3.3.1...v4.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oauthlib/oauthlib/blob/master/CHANGELOG.rst">oauthlib's
changelog</a>.</em></p>
<blockquote>
<h2>4.0.0 (2026-09-28):</h2>
<p>OAuth2.0 Provider:</p>
<ul>
<li><strong>Breaking</strong>: <a
href="https://redirect.github.com/oauthlib/oauthlib/issues/951">#951</a>:
Removed JSONP support from token revocation endpoint.
JSONP has been superseded by CORS for cross-origin requests.
The <code>enable_jsonp</code> parameter has been removed from
<code>RevocationEndpoint</code>
and the <code>callback</code> parameter has been removed from
<code>prepare_token_revocation_request</code>.</li>
<li><strong>Breaking</strong>: <a
href="https://redirect.github.com/oauthlib/oauthlib/issues/919">#919</a>,
<a
href="https://redirect.github.com/oauthlib/oauthlib/issues/920">#920</a>:
Fixed <code>DeviceCodeGrant.validate_token_request</code>
trying to authenticate public clients.
Client authentication validation has been reorganized and is now shared
across <code>AuthorizationCodeGrant</code>,
<code>DeviceCodeGrant</code>, <code>RefreshTokenGrant</code>
and <code>ResourceOwnerPasswordCredentialsGrant</code>: the
<code>grant_type</code> parameter
is validated before client authentication, so requests missing
<code>grant_type</code> now return <code>400 invalid_request</code>
instead of
<code>401 invalid_client</code>.</li>
<li><a
href="https://redirect.github.com/oauthlib/oauthlib/issues/963">#963</a>:
Improved PKCE code comparison</li>
</ul>
<p>Misc:</p>
<ul>
<li><a
href="https://redirect.github.com/oauthlib/oauthlib/issues/904">#904</a>:
Stop installing <code>examples</code> into
<code>site-packages</code>.</li>
<li><a
href="https://redirect.github.com/oauthlib/oauthlib/issues/930">#930</a>:
Add devcontainer, Add Python3.14, Python3.14t.</li>
<li><a
href="https://redirect.github.com/oauthlib/oauthlib/issues/931">#931</a>:
Fix ruff checks about unused variables.</li>
<li><a
href="https://redirect.github.com/oauthlib/oauthlib/issues/932">#932</a>:
Dropped EOL Python 3.8 from CI.</li>
<li><a
href="https://redirect.github.com/oauthlib/oauthlib/issues/934">#934</a>:
Pre-commit hooks autoupdate.</li>
<li><a
href="https://redirect.github.com/oauthlib/oauthlib/issues/938">#938</a>:
Fix typos discovered by typos.</li>
<li>Add OAuthLib Maintainer agent for automated issue/PR triage and
release
management.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oauthlib/oauthlib/commit/145a9a4690cb4d9de30d15fcc2984e34c49df741"><code>145a9a4</code></a>
Release 4.0.0: clarify changelog breaking changes and reformat
entries</li>
<li><a
href="https://github.com/oauthlib/oauthlib/commit/c8344d61492c7ae708cf378ecabab7ee6ab62812"><code>c8344d6</code></a>
Update CHANGELOG.rst</li>
<li><a
href="https://github.com/oauthlib/oauthlib/commit/e172830efd66a2dc1bb34b3bbbf8ee53036a9dac"><code>e172830</code></a>
Release 4.0.0: bump version to 4.0.0 and update changelog</li>
<li><a
href="https://github.com/oauthlib/oauthlib/commit/40b0ab56da3682c2484a4b78bbff309f8025d950"><code>40b0ab5</code></a>
Merge pull request <a
href="https://redirect.github.com/oauthlib/oauthlib/issues/963">#963</a>
from oauthlib/ft/pkcecode</li>
<li><a
href="https://github.com/oauthlib/oauthlib/commit/1b68ceaae02fe62aeaaa3468a8f8082c73830a3a"><code>1b68cea</code></a>
Merge pull request <a
href="https://redirect.github.com/oauthlib/oauthlib/issues/920">#920</a>
from hekhuisk/validate-client-authentication</li>
<li><a
href="https://github.com/oauthlib/oauthlib/commit/c951a1d09f99f14e3240973fa83c4f4287d4753d"><code>c951a1d</code></a>
Organized validate_client functions for all grant to avoid mistake in
grnat i...</li>
<li><a
href="https://github.com/oauthlib/oauthlib/commit/74664d3fe037a354e180e305135c6bab1747a6b0"><code>74664d3</code></a>
Improve PKCE code comparison</li>
<li><a
href="https://github.com/oauthlib/oauthlib/commit/9859b057ecc5d1ad42711af7d58ee471d708ea36"><code>9859b05</code></a>
Merge pull request <a
href="https://redirect.github.com/oauthlib/oauthlib/issues/950">#950</a>
from oauthlib/feature/3.4.0-maintainer-agent</li>
<li><a
href="https://github.com/oauthlib/oauthlib/commit/9bf9b974e0797d2d03cba05854f46e314c730ba6"><code>9bf9b97</code></a>
Merge branch 'master' into feature/3.4.0-maintainer-agent</li>
<li><a
href="https://github.com/oauthlib/oauthlib/commit/1ba7429ad79019289540fd7be27866d7e59f2564"><code>1ba7429</code></a>
Clarify agent instructions</li>
<li>Additional commits viewable in <a
href="https://github.com/oauthlib/oauthlib/compare/v3.3.1...v4.0.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=oauthlib&package-manager=uv&previous-version=3.3.1&new-version=4.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/calibrain/shelfmark/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 01:54:25 -06:00
splitsec2 3633dd3d97 fix: keep file links and API keys out of AllDebrid logs, fix Newznab debug log (#1559)
Two log fixes in the same area, both found while going through the open
code scanning alerts.

AllDebrid: the unlock path logged the file link in full. The last-resort
fallback appends `apikey=` to the link and returns it, and the "Failed
to download from ..." error carries that same link into
`logger.exception`, so the key could land in the log and the traceback.
The links are now logged through `_safe_url` (scheme, host and path
only). The GET unlock fallback also logged the exception text at debug
level, and requests puts the request URL in that message, which includes
`apikey=`. That one now logs the exception type only. This covers code
scanning alert 124.

Newznab: `logger.debug("Newznab API: GET %s params=%s", url, *params)`
star-expands the dict keys into the log arguments, so with debug logging
on it raises `TypeError: not all arguments converted during string
formatting` and the line never prints. Logging `params` as is would
print the API key, so it now logs the sorted parameter names.

Tests: the Newznab one formats the logged line and checks the key is
absent. The AllDebrid ones check the fallback and failure paths log no
query string and that the fallback still returns the link with the key.
All three fail without the change. Ruff and basedpyright are clean,
`tests/newznab` and `tests/prowlarr` pass.
2026-10-23 01:53:08 -06:00
splitsec2 4f97fc9bec fix: keep server paths and URLs out of an error response and a debug log (#1558)
Two small leaks from going through the open CodeQL alerts (code scanning
alerts 100 and 123).

The local download route returned `str(e)` on an OSError, and for a
missing or unreadable file that text is the file's path on the server
(`[Errno 2] No such file or directory:
'/audiobooks/Author/Title.epub'`). #1422 cuts a non-admin's download
path down to the file name everywhere else, so this put it back. The
route now answers "Could not read the file" and the detail stays in the
log.

`should_bypass_proxy` logged the whole request URL at debug when it
could not be parsed. URLs can carry credentials, so it logs only the
exception now.

Each change has a test that fails without it. The full non-e2e suite,
ruff and basedpyright pass.
2026-10-23 01:52:39 -06:00
dependabot[bot] 003df0b686 build(deps): bump cryptography from 46.0.7 to 50.0.0 (#1555)
Bumps [cryptography](https://github.com/pyca/cryptography) from 46.0.7
to 50.0.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst">cryptography's
changelog</a>.</em></p>
<blockquote>
<p>50.0.0 - 2026-07-31</p>
<pre><code>
* **SECURITY ISSUE**:

:func:`~cryptography.hazmat.primitives.serialization.pkcs7.pkcs7_decrypt_der`
and its PEM and S/MIME variants no longer expose distinguishable errors
or
timing when unwrapping a ``RecipientInfo``'s ``encryptedKey``, which
could
act as a Bleichenbacher oracle for callers that decrypt untrusted
messages.
A random key is now substituted on failure, as described in :rfc:`3218`.
  Credit to **@X1AOxiang** for reporting the issue. **CVE-2026-69247**
* Deprecated Diffie-Hellman key exchange over finite fields (FFDH).
  Everything FFDH is deprecated, including the types in
``cryptography.hazmat.primitives.asymmetric.dh`` and loading FFDH keys
or
  parameters with the key loading APIs. Users should migrate to a more
  modern key exchange algorithm.
* Added ``xof()`` class methods to
  :class:`~cryptography.hazmat.primitives.hashes.SHAKE128` and
:class:`~cryptography.hazmat.primitives.hashes.SHAKE256` for
constructing
  algorithm instances configured for use with
  :class:`~cryptography.hazmat.primitives.hashes.XOFHash`.
* The :mod:`X.509 verification &lt;cryptography.x509.verification&gt;`
APIs are now
  considered stable and are subject to our API stability policy.
* Added the :doc:`/cobblestone` recipe, an implementation of the
  Cobblestone-128 and Cobblestone-256 instantiations of the `C2SP
  chunked-encryption specification
&lt;https://c2sp.org/chunked-encryption&gt;`_ for streaming
authenticated
  encryption of large messages.
* Parsing a Signed Certificate Timestamp list now rejects encodings that
carry trailing bytes after the list or after an individual SCT, instead
of
  silently ignoring them.
* Added support for using :class:`~cryptography.x509.Name` as a field
type in
  the :doc:`/hazmat/asn1/index` module.
* Loading a public key or an EC private key now rejects DER where the
``subjectPublicKey`` (or EC ``publicKey``) ``BIT STRING`` declares a
non-zero
  number of unused bits, instead of silently ignoring it.
* Parsing a CRL entry's ``InvalidityDate`` extension now rejects a
``GeneralizedTime`` that carries fractional seconds or another non-DER
form,
matching the strict encoding already required for every other X.509 time
  field.
* :func:`~cryptography.x509.ocsp.load_der_ocsp_request` and
:func:`~cryptography.x509.ocsp.load_der_ocsp_response` now reject a
request
or response whose ``version`` field is not ``v1``, the only version
defined
by RFC 6960, matching the version validation already performed when
loading
  certificates, CSRs and CRLs.
* :class:`~cryptography.hazmat.primitives.hashes.XOFHash` is now
supported
  when building against AWS-LC.
* HMAC (and therefore PBKDF2-HMAC) with SHA-3 hashes is now supported
when
  building against AWS-LC.
* Diffie-Hellman (:doc:`/hazmat/primitives/asymmetric/dh`) is now
supported
  when building against AWS-LC.
&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/pyca/cryptography/commit/dcb7050b807b00392fa9fe2eac7cb362fcf355cc"><code>dcb7050</code></a>
Prepare for 50.0.0 release (<a
href="https://redirect.github.com/pyca/cryptography/issues/15372">#15372</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/53fccd93413a8d7f07d6d8999681f27b75cffa3f"><code>53fccd9</code></a>
Don't leak how PKCS#7 encryptedKey decryption failed (<a
href="https://redirect.github.com/pyca/cryptography/issues/15369">#15369</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/d472f978470fbefa521b86d98b2ecccbbb4d1dd8"><code>d472f97</code></a>
Add <code>from __future__ import annotations</code> to all src/ Python
files (<a
href="https://redirect.github.com/pyca/cryptography/issues/15371">#15371</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/908773d53829fb1466c6db364b31321c3cd8eb9a"><code>908773d</code></a>
Bump downstream dependencies in CI (<a
href="https://redirect.github.com/pyca/cryptography/issues/15368">#15368</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/2cc07cc948948211899bcb0cddd1fddf86e95812"><code>2cc07cc</code></a>
Bump BoringSSL, OpenSSL, AWS-LC in CI (<a
href="https://redirect.github.com/pyca/cryptography/issues/15367">#15367</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/c94ede9f040fa44942f7139772603419000acf66"><code>c94ede9</code></a>
chore(deps): bump ruff from 0.16.0 to 0.16.1 (<a
href="https://redirect.github.com/pyca/cryptography/issues/15366">#15366</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/67a8308dc9ea4cce6056e0f1438f903c208c3f35"><code>67a8308</code></a>
chore(deps): bump virtualenv from 21.7.0 to 21.7.1 (<a
href="https://redirect.github.com/pyca/cryptography/issues/15365">#15365</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/95018ffcdbbc510fd92fc872e3a3e80aa6e58596"><code>95018ff</code></a>
Release the GIL in one-shot AEAD encrypt/decrypt (<a
href="https://redirect.github.com/pyca/cryptography/issues/15361">#15361</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/6954733eaf55a0074abf88f06f7242dfca3a5d02"><code>6954733</code></a>
Release the GIL during DH and DSA parameter generation (<a
href="https://redirect.github.com/pyca/cryptography/issues/15364">#15364</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/6893b94c33e948f6240082461424cfb5da2dacc6"><code>6893b94</code></a>
Import _serialization instead of serialization in x509/extensions (<a
href="https://redirect.github.com/pyca/cryptography/issues/15363">#15363</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/pyca/cryptography/compare/46.0.7...50.0.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cryptography&package-manager=uv&previous-version=46.0.7&new-version=50.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/calibrain/shelfmark/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 01:28:06 -06:00
splitsec2 86fff32297 feat(hardcover): owned books, simpler queries, dead sources and failed releases (#1535)
A request whose book turns out to be in the library is closed with the note `[auto] Already in the library.` instead of sitting in Needs Review. A request an admin handled by hand while a pass was running is skipped. A series label in front of a Calibre title no longer hides an owned book, and a Calibre title marked as another edition (full cast, dramatized, GraphicAudio) is not the book.

When no source matches, up to three simpler forms of the title are tried on each source under the same strict match. Optionally (off by default), an unmatched audiobook request is looked up on Audible US and UK through Audiobookshelf's metadata search and the request says what the store answered. It never declines anything.

A Soulseek peer whose recent transfers all failed, and an AudiobookBay post whose comments say it has no seeders, are tried after the other matches and never excluded. A failed or stalled release is kept out for AUTO_DOWNLOAD_RETRY_FAILED_RELEASE_DAYS and then tried again, and a torrent that died for one request is not offered to another. A request stuck on queued or downloading is settled from the download history. Optionally (off by default) a failed download is retried with another release within minutes.
2026-10-23 01:08:00 -06:00
splitsec2 9d5b47d17b feat(hardcover): retries, error counting and a back-off for requests nothing matches (#1534)
A synced request whose download failed, was interrupted by a restart, or was cancelled by the stall timer goes back to pending after AUTO_DOWNLOAD_RETRY_DAYS (7 by default, 0 turns it off), a few per pass, oldest first. Only what never arrived is retried, the failed release is remembered, and a request is given up on after three failed retries. Downloads cancelled by a person and rejected requests are never retried.

Errors count as errors: a search that failed in one source no longer reads as no match, a throttled Hardcover lookup is an error and not a skip, and a request that blows up doesn't abort the pass. Both summaries carry the error count.

A request for the same Hardcover book and format is skipped when the history already has a finished or running download for it. A request that finds nothing is searched once a day after three no-match passes, then every two days, up to AUTO_DOWNLOAD_BACKOFF_MAX_DAYS (3 by default, 0 turns it off).
2026-10-23 00:58:42 -06:00
splitsec2 4389548deb feat(hardcover): ebooks, audiobooks or both, and stricter matching for automatic downloads (#1533)
A shelf book can be requested as an ebook, an audiobook or both (one request per format), and each request is checked against its own library, source priority list and format guard. Ranking within a source prefers the most downloaded copy, then size, and one m4b is preferred to a set of chapter files unless it is much smaller than the other copies. Soulseek peers are ranked by free slot, queue length and speed.

Automatic downloads refuse multi-book packs, sequels and other works named in the title, study guides, abridged or dramatised versions, two-in-one titles, releases in a language the requester didn't ask for, and an archive for an audiobook request.

Matching folds accents on both sides, drops an alternate title for the search and the match, and reads small numbers the same in any form. AudiobookBay releases with no author in the listing title are judged on the authors credited on the detail page.
2026-10-23 00:41:13 -06:00
splitsec2 ea69db3f8e feat(library): Audiobookshelf library check, and the sync fails closed when a library cannot be read (#1519)
Adds an Audiobookshelf provider for the library check, next to the Calibre one. It reads the server over its REST API (title, author, ISBN and ASIN per item), answers for audiobooks, and has its settings in General with a test button that uses the unsaved form values. Read only.

The Hardcover sync and automatic downloads now fail closed when an enabled library cannot be read: the sync skips its cycle and an automatic download holds the request. A library that listed items at the last index and now lists none counts as a failed read. Badges still fail open.
2026-10-23 00:21:40 -06:00
ProcyonX1 99a6aa206b feat(metadata): add Deutsche Nationalbibliothek (DNB) metadata provider (#1547)
## feat(metadata): add Deutsche Nationalbibliothek (DNB) metadata
provider

This adds the Deutsche Nationalbibliothek (DNB) as a metadata provider.
It covers German editions far better than the existing providers.
No API key, disabled by default, and the same pattern as the other
providers.

It uses DNB's public SRU interface and parses MARC21-XML. Thats one
reason why this needs more code than the Google Books or Open Library
providers. The others are the search (DNB has no relevance ranking) and
the language filter, see below.

### Notes
- **Search box.** Search-box text goes from precise to loose until a
stage has hits: the complete title, then the title as a phrase, then
every word in a title or a person's name, last without German articles.
- **"Only show editions in my book languages"** (optional, on by
default). DNB also catalogs a lot of translations. DNB filters by the
searching user's Default Book Languages, else the system default.
- **No covers.** DNB's cover service is behind Anubis bot protection, so
the provider returns no cover URLs.
- **Proxy support** already included like Open Library since #1526


### Changes outside the provider
- DNB is in the onboarding dropdown.
- Calibre's `dnb-idn` identifier is mapped, so DNB results show library
ownership
- In the env-var docs I added only the DNB section. Regenerating the
whole file on main currently also reorders unrelated sections and drops
`SHELFMARK_API_KEY_READONLY` (and the Databáze knih section sits inside
the Moly.hu block).

### Ideas
- **Deduplication.** DNB lists every edition. Kafka's "Die Verwandlung"
has around 200 German editions of the same text. Grouping them would
touch the API, the frontend and release search.
- **Language-aware metadata search** for all providers. The other
providers ignore Default Book Languages in metadata search. The
`user_id` added here could serve them too.
2026-10-22 20:37:15 -04:00
2007384058 feat(sources): add Webshare.cz as a release source (#1543)
## What

Adds [Webshare.cz](https://webshare.cz), the Czech file host, as a
release source for ebooks and audiobooks. It follows the Libgen source:
disabled by default, with a settings tab for credentials and a **Test
Login** button that reports whether the account is VIP.

## Why

Webshare is one of the main places Czech and Slovak ebooks and
audiobooks are shared, and none of the existing sources reach it.
Together with the Databáze knih metadata provider (#1479), this lets
Universal mode find Czech and Slovak titles end to end.

## How

- **API client** (`webshare/api.py`): Webshare's XML API (`POST
/api/<endpoint>/`). Login is the salted exchange the API documents:
fetch the salt, send `SHA1(MD5_CRYPT(password, salt))` plus an MD5
digest. Python dropped the `crypt` module in 3.13, so md5-crypt is a
small pure-Python port, checked against `openssl passwd -1`. The session
token is cached per account and refreshed once when an authenticated
call fails. File-level errors (`FILE_LINK_FATAL_*`) are not retried. XML
is parsed with `defusedxml`.
- **Search** (`webshare/source.py`): Webshare matches file names only,
so the file name becomes the release title and its extension the format.
Queries are title + author, then title only, or the manual query.
Results are filtered to the configured `SUPPORTED_FORMATS` /
`SUPPORTED_AUDIOBOOK_FORMATS`, plus `zip`/`rar` for audiobooks, since
they are usually uploaded as archives. Password-protected files are
skipped. The language is guessed from tags in the name (`CZ`, `SK`,
`ENG`, ...), and the vote balance is a sortable column. API failures
raise `SourceUnavailableError`.
- **Download** (`webshare/handler.py`): resolves a time-limited link per
attempt with `file_link`, then streams it into `TMP_DIR` with progress
and cancel support. Large audiobook archives are not buffered in memory.
- **Settings**: `WEBSHARE_ENABLED`, `WEBSHARE_USERNAME`,
`WEBSHARE_PASSWORD` (a `PasswordField`, already covered by the
`_PASSWORD` redaction in `genDebug.sh`), and `WEBSHARE_MAX_RESULTS`. The
`docs/environment-variables.md` section was added.

## Testing

- `tests/webshare/`: 31 offline tests. They cover md5-crypt vectors,
password hashing, XML parsing, token reuse and re-login, non-retried
file errors, availability gating, format filtering, query fallback,
release mapping, language guessing, and the handler's streaming,
small-file rejection, link errors and cancel.
- `ruff check` and `ruff format --check` are clean. The rest of the unit
suite fails the same way with and without this change: Windows-only
tests on my machine.
- Verified live against webshare.cz: search parsing and the salt
endpoint's error path.
- Still a draft: I haven't yet verified login and download with a real
account.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-22 20:30:01 -04:00
48ae3dbef4 feat: optional Hardcover wishlist sync with automated downloading (1 of 5) (#1516)
This replaces #1047, which @InfiniteAvenger opened and calibrain offered
to re-review. It is Caleb's feature commit with his authorship kept,
rebased onto current main, with small fixes, tests and a docs page on
top. Everything is opt-in and off by default, so nothing changes for
anyone who doesn't turn it on.

What it adds is a **Settings, Hardcover Sync** tab with three parts that
can be switched on separately:

- **Shelf sync**: a Hardcover shelf (Want to Read by default) is pulled
into requests on a schedule, or with a Sync now button. Requests carry
the Hardcover metadata and cover.
- **Automatic downloads**: synced requests are approved and a release is
picked from a source priority list. A strict title, author and format
match (plus a seeder minimum for torrents) decides, so anything without
a confident match stays pending for manual review.
- **Skip books you already own**: sync and automatic downloads ask
whichever libraries are enabled under Library Check (Calibre today) and
skip a book that is already there.

On top of Caleb's commit I made the request owner a lookup instead of
assuming user id 1, sent synced cover URLs through the proxy when the
request is created, got ruff and basedpyright clean, and added tests and
`docs/hardcover-sync.md`. His commit also had its own Audiobookshelf
settings and a Test library connection button, written before the
library check was split into providers. The button would have raised a
TypeError against the current `test_connection`, so those settings are
gone from this tab and an Audiobookshelf provider comes as a separate
PR, which is the part of #1047 that is missing here (for now
anyways...).

I've run this daily for about a couple of weeks. Ruff, basedpyright and
the backend suite pass (4426 passed).

This is 1 of 5. As calibrain suggested, the rest are stacked on this
one, each saying which number it is.

Closes
https://github.com/calibrain/shelfmark/pull/1047#issuecomment-6302071588

---------

Co-authored-by: InfiniteAvenger <calebewest02@gmail.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-22 20:27:47 -04:00
splitsec2andCaliBrain 72b5d04939 perf: cut repeated work on the status and activity paths (#1545)
Two small cuts to work that repeats on every poll or request.

The delivery-state sync behind /api/status and the activity snapshot
listed every fulfilled request (SELECT * plus a JSON parse of book_data
and release_data per row) before it looked at the queue. That history is
never purged, so an idle instance paid for it on every poll. It now
returns straight away when no queue bucket holds a task, since nothing
could map to a request then. Results and emitted updates are unchanged.
The activity snapshot gains less from this, because its status merges
download history rows, so it is usually not empty.

In proxy auth mode the before-request hook looked the user up by name
and by session id on every API call, cover images included, each on a
new SQLite connection. UserDB.get_user_cached answers repeat lookups
from memory for up to five seconds, bounded at 256 entries. create_user,
update_user and delete_user drop the cache as soon as they commit, and a
lookup that overlaps a write is not stored, so a role change or deletion
made in the app applies on the next request. Changes made outside that
UserDB instance (another process, or the separate instances some helpers
open) show within the five seconds. Only the middleware uses the cached
path; every other get_user caller is unchanged.

Each change has a test that failed before it: one counts list_requests
calls for an empty queue, the others count get_user calls across
repeated lookups and middleware runs, check expiry with a patched clock,
and check that writes and caller mutations do not leave a stale row
behind. The full suite passes (4432 passed, 48 skipped, e2e excluded),
as do ruff and basedpyright on the changed files.

I also looked at throttling the full status_update broadcast when only
the progress message changes during torrent and usenet polling, and left
it out. Those handlers poll every 2 seconds and
DOWNLOAD_PROGRESS_UPDATE_INTERVAL defaults to 1 second, so a throttle on
that interval would skip nothing at the default setting. A longer window
would slow the speed and ETA text in the UI, and without a trailing
flush it would hide the last message of a quick burst, such as "Waiting
for bot response" arriving just after "Requesting file from bot", for
the whole wait that follows.

---------

Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-22 20:27:07 -04:00
splitsec2andCaliBrain 237ddd53a2 fix(redaction): a non-admin's status message loses the links it quotes (#1541)
#1422 hid `source_id` and the download path from non-admins but left the
status message alone. A failed add stores the client's exception text
there, for example `401 Client Error: Unauthorized for url: <full url>`,
and for a requests error that URL carries the path and query: an indexer
key, a tracker passkey, a peer name. It reached the owner through
`/api/status`, `/api/activity` and the `status_update` socket event.

`redact_download_payload` now replaces every link in `status_message`
with `(link removed)`. That covers the live queue, the socket push and
the history snapshot, since all three go through it. Messages without a
link are unchanged and admins still see the full text.

Tests cover the payload, a whole status snapshot, and messages that must
stay as they are. They fail on main and pass here.

Found in a Claude pass over 1.5.0.

---------

Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-22 20:26:47 -04:00
splitsec2 a430341a93 perf: cut repeated work on search and cover paths (#1544)
I went through what Shelfmark does per search and per cover and measured
the pieces that showed up. Four of them are cheap to fix, so this is one
PR. Shelfmark runs on a single gevent worker, so any of these blocks
every other request while it runs, and I'm assuming a lot of people run
it on small hardware (a Pi, say).

Cover cache. Every cache hit rewrote the whole `cache_index.json` just
to bump the entry's last-access time. On my box that is 3.7 ms of CPU
per hit at 500 entries and about 100 ms at 15,000 (2.2 MB written each
time), and a results page asks for around 40 covers. The access time now
stays in memory and the index is written at most every 30 seconds, or
whenever something else saves it. A crash inside that window loses some
access times, which only changes eviction order.

Settings reload. `config.refresh()` rebuilt the cache by reading and
parsing a tab's JSON file once per field, so about 250 parses per
refresh, 100 ms of CPU, and the metadata search, providers and config
routes each trigger it. It now reads each file once per rebuild (several
tabs share `settings.json`, so the memo is keyed on the file path).

Library match. When the library check is on, each search result is
compared against every library entry, and the title was split into words
again for every entry. The words are now computed once per result. I
measured 33 ms per result at 5,000 library entries and 106 ms at 20,000,
which is a second or more per page of 40 results. The matching itself is
unchanged.

Cover URL probe. `is_covers_cache_enabled()` creates and deletes a file
in the config directory to check it is writable, and it runs for every
cover, queue task and history row. The answer is remembered for 60
seconds. The probe is 0.045 ms on its own, but it is called a few
hundred times per request in the worst case.

Each change has a test that fails without it (call counts on the index
saves, file opens during a refresh, tokenisation calls, and probe
calls). Ruff, basedpyright on the changed files and the non-e2e suite
pass. The timings are from a dev machine with an empty config, so the
real numbers depend on cache and library size.
2026-10-22 20:24:57 -04:00
splitsec2 2668705bfa perf: reuse connections and cache Anna's Archive download counts (#1546)
Two small changes that stop Shelfmark from opening a new HTTPS
connection for requests that go to the same host over and over.

Anna's Archive download counts. Every search result gets its count from
`/dyn/md5/inline_info/<md5>`, and each of those was a bare
`requests.get`, so a search with 50 results opened 50 TCP and TLS
connections to the mirror. `search_books` also runs once per title
variant, and the variants of one book mostly find the same files, so the
same md5 was looked up again for every variant that found it, and again
when the release list was reopened. The lookups now share one
`requests.Session`, and a successful count is kept for five minutes in a
bounded `CacheService` (the same class the metadata cache uses, as its
own instance, so it does not depend on the metadata cache toggle). A
lookup that fails or comes back without a count is not cached, so it is
retried on the next search just like today. The URL, headers and 5
second timeout are unchanged.

Debrid clients. Real-Debrid, AllDebrid, Debrid-Link and TorBox also used
the bare `requests` helpers. The download handler polls `get_status`
every two seconds for each active job, so every poll was a fresh TLS
handshake with the debrid API. Each of those modules now keeps one
`requests.Session` and sends its API calls through it, the way the
qBittorrent, Deluge, Prowlarr and Newznab clients already do. Headers,
timeouts, `verify` and error handling are still passed per call exactly
as before. The existing tests that patched
`<module>.requests.get/post/request` now patch
`<module>._session.<verb>` instead; nothing else in them changed.

How I checked it: each change has a test that fails on main and passes
here. They count the requests that reach `requests.Session.request` and
the sessions built while doing it, with no network. On main, three polls
of each debrid client build three sessions, and two overlapping batches
of AA results look `bbb` up twice. There are also tests for the count
cache expiring (with a faked clock) and for a failed lookup not being
cached. Full suite: 4432 passed, 48 skipped. ruff and basedpyright are
clean on the changed files.

I also looked at caching `/api/releases` on the server and left it out.
The release modal already caches each book's results per source and
content type in the browser for five minutes (longer for IRC and slskd
through `cache_ttl_seconds`), and that cache survives closing and
reopening the modal, so reopening it does not run a new search today. A
server cache would only help after a page reload, and it would quietly
undo the modal's "apply filters" and manual search refetches, which drop
the browser cache on purpose, unless the frontend also learned to send a
bypass. That did not seem worth it for this PR.
2026-10-22 20:24:40 -04:00
splitsec2 08fdb7ea87 fix(startup): the reconcile guard catches the same errors the rest of main.py does (#1540)
The start-up reconcile runs at import, before the coordinator starts,
inside a try that named five exception types and left out `TypeError`.
`main.py` already defines `_IMPORT_OPERATIONAL_ERRORS` for this shape
and the other module-level guards use it, so this switches to it. An
unexpected `TypeError` from the reconcile would otherwise fail the
import of `shelfmark.main`, and the worker would fail to boot on every
restart.

I didn't use `except Exception` because BLE001 is on and nothing in
main.py does.

The test reloads main with the reconcile raising `TypeError`, and with
`OSError` as the control (that one already passes on main). Full non-e2e
suite passes, ruff and basedpyright are clean.

Found in a Claude pass over 1.5.0.
2026-10-22 20:22:21 -04:00
splitsec2 f560b31ee4 fix(db): wait up to 30 s for a busy writer instead of SQLite's 5 s default (#1539)
The users, download history and activity view-state databases open their
connections with SQLite's default busy timeout of 5 seconds. A start-up
migration, the restart reconcile, or any statement that overlaps a
backup or a second process raised "database is locked" after 5 seconds,
and the reconcile finished only part of its work.

One shared `DB_BUSY_TIMEOUT_SECONDS` (30) in `core/utils.py`, used by
all three. The test reads SQLite's `busy_timeout` pragma back from each
connection, so it doesn't need a real lock fight.

I left `UserDB.initialize()` without a guard on purpose. With 30 seconds
the wait covers a backup, and swallowing a schema failure there would
hide a worker that can't run.

Found in a Claude pass over 1.5.0.
2026-10-22 20:21:49 -04:00
splitsec2 2d9491e063 docs(settings): say that the per-source limit replaces Max Concurrent Downloads (#1542)
With Max Concurrent Downloads Per Source above 0 the download pool is
sized per source and a task is admitted when its own source is below the
limit. Max Concurrent Downloads isn't read at all in that mode, so 3 per
source across 3 busy sources runs 9 at once. Neither description said
so.

The per-source text now says it replaces the global limit and what the
total can be, and the global one says it isn't used while the per-source
limit is set. Text only, no behaviour change.

I changed the two rows in `docs/environment-variables.md` by hand.
Running `scripts/generate_env_docs.py` on main today also drops the
`SHELFMARK_API_KEY_READONLY` entries and changes the slskd anchor, so
the file looks hand-edited since it was last generated, and I didn't
want to fold that into this. The two rows match what the generator
produces for them.

Found in a Claude pass over 1.5.0.
2026-10-22 20:20:56 -04:00
splitsec2 e27fed1d40 fix(queue): a late progress update no longer reopens a finished task (#1538)
#1429 made the first terminal status win, but the guard only refused
terminal to terminal changes. A worker's poll that reports DOWNLOADING
after a cancel still overwrote CANCELLED (the poll loop calls the status
callback before it waits on the cancel flag), and the COMPLETE or ERROR
that followed was then accepted as a first terminal status, so the
terminal hook ran a second time.

This refuses any status change away from a terminal status. `add()` and
`enqueue_existing()` reset the status themselves, so retries are
unaffected.

The new test cancels a downloading task, sends DOWNLOADING and then
COMPLETE, and expects CANCELLED and one hook call. It fails on main and
passes here. Full non-e2e suite passes, ruff and basedpyright are clean.

Found in a Claude pass over 1.5.0, same as my other small fixes from it.
2026-10-22 20:19:16 -04:00
splitsec2 395c331b4a fix(search): give each provider its own slice of the search budget (#1537)
Fixes #1531.

All Direct Download providers share the one search budget
(`RELEASE_SEARCH_TIMEOUT`, 300s). Anna's Archive runs first, and when
its bypass keeps failing the retries use up the whole budget. OceanofPDF
then sees an expired deadline, skips its queries, and the search raises
Anna's Archive's error even though OceanofPDF never got a turn.

I didn't split the budget evenly, since the deadline module itself says
a cold-start Anna's Archive solve can legitimately take 60 to 120s and a
150s or 37s slice would break setups that work today. Instead
`search_deadline.unit_deadline(waiting=n)` opens a child deadline for
one unit of work. It gets the parent's remaining time minus 30s for each
unit still waiting, never less than 30s and never more than the parent
has left. A single provider still gets everything, a fast provider's
unused time rolls on to the next, and a stuck one stops at its own limit
with the reserve intact.

It's used in the provider loop in `DirectDownloadSource.search`, and in
the source loop in `/api/releases` since it's the same shape and four
lines. With several sources enabled the first one now gets 30s less per
source behind it, which is still well above a cold solve for the usual
two or three.

Tests: a stuck first provider no longer starves the second (fails on
main, passes here), a lone provider gets the full budget, and a child
never outlives its parent. Two existing tests in
`test_releases_api_budget.py` tripped the deadline in force from inside
the source, which is now the child, so they use a short request budget
instead. ruff, basedpyright on the changed files and the non-e2e suite
are clean.

OceanofPDF is inactive on my own instance (no mirror URL set), so I
haven't reproduced this live. It's verified by reading the code and by
the tests. I had Claude do the pass on this one.
2026-10-22 20:17:44 -04:00
splitsec2 8e425da527 refactor: one default and one reader for the Supported Book Formats list (#1532)
The default for Supported Book Formats (`epub, mobi, azw3, fb2, djvu,
cbz, cbr`) was written out in five places: the settings registry,
`postprocess/policy.py`, `irc/parser.py`, Prowlarr's `source.py` (added
in #1490) and slskd's `source.py` (added in #1428). Both of those two
arrived in 1.5.0, and both are mine, so this is cleaning up after myself
as much as anything.

The setting was also read three different ways. Post-processing split on
commas only. slskd split on commas and spaces and stripped a leading
dot. IRC split on commas and kept the dot. Prowlarr split on commas and
kept `""` as a format when the value was an empty string. So `.epub` or
`epub mobi` worked in one source and not another.

This puts `DEFAULT_EBOOK_FORMATS` and `normalize_format_list` in
`core/utils.py` next to `AUDIOBOOK_FORMATS`, and the registry,
post-processing, IRC, Prowlarr and slskd all use them. I took the most
lenient reading of the three (comma or space split, leading dot dropped,
empties ignored, default when nothing is left), so no existing config
gets stricter. I put the reader in `core/utils.py` and not in
`policy.py` because the release sources can't import `policy` without
pulling in the whole post-processing package.

A config with a sensible list reads exactly as before. The only
differences are for malformed values: an emptied setting or an empty
string now falls back to the default in every place, where IRC used to
filter everything out and Prowlarr treated `""` as a format.

The audiobook default is a separate story and I left it alone: the
registry and slskd default to every processable audiobook format plus
the archives, while post-processing and IRC fall back to `m4b, mp3`.
They only differ when the setting is unset or emptied, but they do
differ, and I'd rather ask which one you want than pick one here.

Ruff, basedpyright on the changed files and the backend suite pass (4400
passed, e2e not run). New tests cover the reader and the two fallbacks.
2026-10-22 15:32:00 -04:00
Amalkrishna A SandCaliBrain a11a63a29e feat(notifications): add {User}/{Email} placeholders to per-user routes (#1499)
Closes #1130.

Per-user notification route URLs can now use `{Email}` and `{User}`,
filled in from each user's account at send time, the same way `{User}`
already works in destination paths. One default route like
`mailtos://user:pass@smtp.example.com?to={Email}` now reaches every user
at their own address, with no per-user setup.

- Values are URL-encoded (`alice+books@example.com` keeps its `+`);
placeholders are case-insensitive.
- A route that needs a value the user doesn't have (e.g. no email on
file) is skipped for that user; other routes still send.
- The user lookup only runs when a route contains a placeholder.
- The personal "Test notification" button expands the placeholders too,
so testing a `{Email}` route works.
- Added to the routes setting help, `docs/users-and-requests.md`, and
tests.

@calibrain ready for review.

---------

Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-22 15:29:34 -04:00
dependabot[bot] 182e80f894 build(deps): bump publicsuffixlist from 1.1.0.20261017 to 1.1.0.20261018 (#1527)
Bumps [publicsuffixlist](https://github.com/ko-zu/psl) from
1.1.0.20261017 to 1.1.0.20261018.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/ko-zu/psl/commits">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=publicsuffixlist&package-manager=uv&previous-version=1.1.0.20261017&new-version=1.1.0.20261018)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-22 03:21:05 -04:00
CaliBrain c5af6b9ae6 ci(jules): review the whole PR diff, not just the latest push (#1529)
jules-pr-reviewer v0.0.2 reviewed only before...head on synchronize.
After
"Update branch" merged main into fork PRs, that range was main's
commits, so
of their own changes. v0.0.3 of the calibrain fork always reviews the
PR's
full diff. Also correct the fork workflow comment: jules-forks has no
required reviewers by design, so runs don't wait for approval.
2026-10-22 03:20:45 -04:00
c43da4537d fix(network): apply HTTP proxy to Open Library and Prowlarr requests (#1526)
Fixes #1524

Open Library metadata searches and Prowlarr API calls used
`get_ssl_verify` but never `get_proxies`, so the HTTP proxy set in
Settings → Network was not applied to their HTTPS requests. Both now
pass the configured proxies. Relying on `requests`' `trust_env` with
only `HTTP_PROXY` set leaves the same gap for `https://` destinations.

Verification (Linux, `uv run --frozen pytest`):
- New tests `tests/metadata/test_openlibrary_proxy.py` and
`tests/prowlarr/test_api_proxy.py`: 4 passed. With the source change
reverted they fail (2 failed, 2 errors).
- `tests/metadata` + `tests/prowlarr`: 949 passed, 42 skipped.
- The full suite in my environment showed 61 failures and 26 errors
outside these areas. I did not compare them against `main`, so I'm not
claiming the full suite is green here; CI will show it.
- `ruff check` and `ruff format --check` on the changed files pass.

Prepared with AI assistance; reviewed and tested by me before
submitting.

Co-authored-by: dbdefault <246079841+dbdefault@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-22 02:47:43 -04:00
CaliBrain 9d5bcf0c58 ci(jules): review fork PRs through a gated pull_request_target workflow (#1528)
Fork PRs get no secrets under pull_request and Dependabot runs get only
Dependabot secrets, so JULES_API_KEY was empty and every such run failed
at
config. The same-repo workflow now skips them, and a new
pull_request_target
workflow reviews fork PRs behind maintainer approval on the jules-forks
environment, without checking out PR code. Both use calibrain's fork of
jules-pr-reviewer, since upstream refuses pull_request_target.
2026-10-22 02:40:50 -04:00
CaliBrain d887942630 fix(search): name the proxy when a gateway cuts a search off (#1522)
A reverse proxy whose read timeout is shorter than the release search
budget
(nginx defaults to 60s) answers a slow search with its own 504 page.
describeSearchFailure found no server message there and fell back to
"Unable to reach download source. Network may be restricted or mirrors
blocked.", which sent users off changing mirrors (discussion #1520).

- 504 and Cloudflare's 524 now say the proxy stopped waiting and that
its
  read timeout should be at least the release search timeout.
- A 502/503 with a non-JSON body keeps fetchJSON's "Server unavailable"
  wording instead of the mirrors line.
- docs: the root-path nginx example sets proxy_read_timeout and
  proxy_send_timeout like the subpath ones, and a new troubleshooting
  section covers searches that time out behind a proxy.
2026-10-22 01:40:00 -04:00
eab8f7bc9a Add Advanced Jules PR Reviewer action (#1523)
This PR adds the Advanced Jules PR Reviewer workflow to automatically
review PRs. It is configured to run on forks automatically as requested
by setting `skip_forks: false`. JULES_API_KEY and GITHUB_TOKEN are
mapped correctly as per documentation.

---
*PR created automatically by Jules for task
[10601196597817548410](https://jules.google.com/task/10601196597817548410)
started by @calibrain*

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: calibrain <191882101+calibrain@users.noreply.github.com>
2026-10-21 14:25:27 -04:00
CaliBrain 1aa9846f22 fix(download): trust a pinned AA mirror and repair the full e2e profile (#1518)
The destination guard from the oceanofpdf/SSRF fix (f837506) trusts only
hosts in
the mirror lists and refuses any other host that resolves to a private
address.

The full e2e profile has failed on every PR since then: its AA mirror
was mock-aa,
but the slow-download links pointed at cf.mock.test (172.30.0.11). The
guard refused
the slow-download page before the internal Chrome bypasser ever started,
so the
download ended with "All download sources failed". Adding cf.mock.test
as a second
AA mirror would not help: AAMirrorSelector.rewrite would then move the
gated link
onto mock-aa, and the test would pass without Chrome solving anything.
The profile
now uses the gate as its only AA mirror. The cloudflare mock takes
CF_GATED_PATHS,
and the full profile challenges only /slow_download/, so search, detail
and the
final file pass through while the download still needs Chrome. The
unused
SLOW_DOWNLOAD_BASE indirection is gone.

The same allowlist missed a supported setup: Primary Mirror
(AA_BASE_URL) may pin a
URL that is not in the mirror list, and network uses it as the active AA
base. With
it on a LAN address, every AA request was refused. The guard now trusts
the pinned
URL too (mirrors.get_pinned_aa_base_url), and
has_aa_mirror_configuration reuses
the same helper.

download_url also ran the guard a second time outside its try block,
which repeated
the DNS lookup and could raise instead of returning None. The duplicate
call is gone.
v1.5.0
2026-10-21 11:19:48 -04:00
DBVamsiandCaliBrain 2fa0ad27f3 Fix [BUG] Search "Options" move out of the way when you try to click them (#1468)
Fixes #1301.

## What changed

## Summary

**Root Cause (Issue #1301):**
The SearchBar component uses a `useDismiss` hook that closes the main
search menu on `mousedown` events occurring outside of `selectorRef` and
`controlsPanelRef`. However, the AdvancedFilters panel (opened via the
"Options" button) is rendered as a sibling component outside of
`controlsPanelRef`. When clicking on dropdown options inside
AdvancedFilters, the `mousedown` event bubbles up to the document,
triggering `useDismiss` and collapsing the main menu.

**Fix:**
Added `onMouseDown={(e) => e.stopPropagation()}` to the `settingsForm`
div in `AdvancedFilters.tsx`. This prevents the `mousedown` event from
bubbling up to the document level, so the `useDismiss` hook in SearchBar
never sees the event and the main menu stays open.

**Test:**
Created `tests/frontend/test_search_menu_dismiss.py` with 3 tests:
1. `test_advanced_filters_prevents_mousedown_bubbling` - Verifies the
fix is in place
2. `test_advanced_filters_container_has_onmousedown` - Verifies the
handler is on the correct element
3. `test_searchbar_uses_usedismiss_for_menu_closing` - Documents the
existing dismissal behavior

**Verification:**
- Tests pass with the fix: ✓
- Tests fail without the fix: ✓ (2 tests fail as expected)
- Existing tests still pass: ✓ (215 tests in config/)

## How it was verified

- test(s) added/changed: `tests/frontend/test_search_menu_dismiss.py`
- on the original code the new test fails (exit 1)
- with the fix it passes (exit 0)
- full test suite with the fix: exit 1, no new failures vs. baseline
(exit 1) (153.7s)

This was worked on in conjunction with AI tools.

Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-21 10:33:45 -04:00
Desislav LesovandCaliBrain fc8a5b9230 fix(prowlarr): hide results whose title extension is not a supported format (#1490)
Closes #1481

## Problem

Plain (non-enriched) indexers such as Zamunda, Knaben or LimeTorrents
return titles like `Иван Вазов - Под игото.doc`. They show next to the
epubs. Picking one downloads the file, then post-processing discards it
because `doc` is not in `SUPPORTED_FORMATS`.

## Change

- `_unsupported_title_extension()` reads a trailing file extension from
the release title. When it is a known file format that is not in
Supported Book Formats, the result is hidden.
- Kept: titles with no extension, `[EPUB]`-style tags, dotted titles
like `Jane.Eyre.by.Bronte` (only known file extensions count), archives
(`zip`, `rar`, `7z`), and audiobook searches.
- New Prowlarr setting `PROWLARR_HIDE_UNSUPPORTED_FORMATS` ("Hide
results in formats you did not enable"), default on.
- One info log line per search with the hidden count; a debug line per
hidden title.
- `docs/environment-variables.md`: added only the new setting's rows.
Running `scripts/generate_env_docs.py` on current `main` also changes
unrelated lines (`SHELFMARK_API_KEY_READONLY`, the slskd anchor), so I
left those alone.

## Tests

- New `TestHideUnsupportedFormats` in `tests/prowlarr/test_source.py`:
the extension helper (parametrised), audiobook bypass, comma-separated
config, and a full `search()` with the setting on and off.
- `tests/prowlarr`: 784 passed. Ruff lint/format, vulture and
basedpyright on the changed files are clean.
- Full suite on macOS: the same 84 bypass/entrypoint failures as on
`main` (browser extra and Linux permissions), none new.

I ran an earlier version of this as a local patch on v1.4.0 against a
real Prowlarr + Zamunda setup: the `.doc` row is gone and epubs stay.

Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-21 10:26:02 -04:00
CaliBrain d42494c696 fix(tor): survive container restarts and run Tor as debian-tor (#1517)
With USING_TOR=true, any restart that reuses the container (docker
restart, a Docker daemon restart, a host reboot) put it in a restart
loop. Only recreating the container ended it.

Tor appends to /var/log/tor/notices.log, and the file survives the
restart. tor.sh waited for Tor by grepping that log for "Bootstrapped
100%", so the previous boot's line passed at once, before Tor had
connected to anything. The NAT rules then went live, Tor could not
finish bootstrapping behind them, the connectivity check could not
resolve check.torproject.org, and the next boot found the same stale
line. tor.sh now moves the previous log to notices.log.prev before it
starts Tor, so the wait and the watchdog only see this boot's output.

Tor could not finish behind the NAT rules because it ran as root. The
rules exempt only debian-tor's traffic from the transparent redirect, so
every relay connection Tor opened after they went live was redirected
into its own TransPort: the log shows dozens of TLS handshakes dying.
This also meant a Tor that lost its guard could never reconnect, on any
kernel. torrc now has `User debian-tor` and `DataDirectory
/var/lib/tor`. Tor still binds DNSPort 53 as root, then drops. It opens
its log after dropping and refuses to start if it cannot, so tor.sh
hands the fresh log to debian-tor first.

The check also failed without a word. `RESULT=$(curl -s ...)` under
`set -e` ended tor.sh with curl's exit status, so the only trace was
ExitCode=6 (could not resolve host) in `docker inspect`. A reply that
was not the expected JSON did the same through grep. The check now:
- retries twice, 10s apart, since a fresh circuit can fail its first
  lookup;
- logs each failure with curl's exit status and error;
- says when it gives up and prints the last Tor log lines;
- still stops the container when traffic does not go through Tor.

- Reproduced on the v1.4.0 image (tor.sh is unchanged since then): after
  one `docker restart` the container restarted 9 times in 150s, each
  boot ending at "Verifying Tor connectivity...".
- With the new tor.sh mounted into the same image, the container went
  through 2 restarts in a row. Each boot verified Tor and reached
  gunicorn within 15-21s, and the restart policy never had to step in.
  Tor runs as debian-tor and its logs belong to it.
- Restarting Tor (`supervisorctl restart tor`) once the NAT rules were
  live, so it had to open new relay connections: as debian-tor it
  bootstrapped again in 4s and traffic still went through Tor. As root
  it had not bootstrapped after 120s, 1775 TLS handshakes had died, and
  curl could not resolve check.torproject.org (exit 6).
- A SIGHUP, which the rotation monitor sends every 5 minutes, keeps
  DNSPort 53 working after the drop to debian-tor.
- 9 new tests in tests/config/test_tor_script_rules.py. 8 of them fail
  on the old tor.sh; the 9th checks that traffic outside Tor still stops
  the container. Three need `grep -P` and skip on macOS, so I also ran
  the file in the Debian image: 23 passed.
- The `make python-checks` tools pass (ruff check and format,
  basedpyright on the app and tests, vulture). The non-e2e suite
  passes: 4366 tests on 86943f5.

Fixes #1502
2026-10-21 10:24:51 -04:00
amura11andClaude Sonnet 5.5 ceb23dda7c feat(clients): separate audiobook download directory for torrent clients (#1500)
## Summary

Related to #1048 (covers the "separate book and audiobook locations"
request, not per-category routing).

Every download client already had a separate audiobook label/category,
but the four torrent clients only had a single save directory, so books
and audiobooks ended up mixed in the client's download folder.

Each torrent client (qBittorrent, Transmission, Deluge, rTorrent) gets
an opt-in **Separate Book and Audiobook Directories** toggle
(`<CLIENT>_SEPARATE_DOWNLOAD_DIRS`, default off):

- **Off (default):** unchanged. The single `<CLIENT>_DOWNLOAD_DIR` is
used for everything, so existing setups behave exactly as before.
- **On:** `<CLIENT>_DOWNLOAD_DIR_BOOK` and
`<CLIENT>_DOWNLOAD_DIR_AUDIOBOOK` replace the shared field. A directory
left empty means the client's own default; it never falls back to the
shared directory or another Shelfmark setting.

The content type was already passed to each client's `add_download`, so
a small shared helper (`resolve_download_dir`) does the selection.

Usenet clients are unchanged: their save location comes from the
category configured in the client, and a separate audiobook category is
already sent.

## Screenshots

Default Setting
<img width="817" height="271" alt="Screenshot 2026-10-20 at 14-54-26
Shelfmark"
src="https://github.com/user-attachments/assets/29941f83-9034-4ea5-bcb2-8e91ce77e63a"
/>

Separate Locations
<img width="817" height="425" alt="Screenshot 2026-10-20 at 14-54-58
Shelfmark"
src="https://github.com/user-attachments/assets/772b7194-a072-4945-bac5-b6959550fd75"
/>


## Not included

Routing to many folders by document type (the main request in #1048)
still only exists for Direct download via Content-Type Routing.
Extending it to torrent and usenet sources needs a decision on what to
route by.

## Testing

- `pytest tests --ignore=tests/e2e` passes (3561 passed); ruff clean.
The `tests/e2e/platform` suite needs a running cluster and was not run.
- New unit tests for the helper (including no fallback to the shared
directory) and a qBittorrent add test covering book vs audiobook
directories.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 10:23:14 -04:00
splitsec2 86943f5a77 chore: drop three unused imports that fail Python Quality (#1514)
Python Quality is failing on new PRs because of three unused imports on
main (it did on #1513): `ipaddress` in `core/image_cache.py`,
`threading` in `core/notifications.py` and `email.utils.parseaddr` in
`download/orchestrator.py`. The code that used them changed in the last
round of merges and the imports stayed behind.

This is `ruff check --fix --select F401` on those three files and
nothing else. Ruff, basedpyright and tests/core plus tests/download
pass.
2026-10-21 02:30:34 -04:00
splitsec2 621d14e1a9 fix(activity): put dismiss-many back together after the #1507 and #1508 merges (#1513)
#1507 and #1508 touch the same handler, and the merged result is wrong
in two places. `effective_existing` is read before it is assigned, so a
Clear Completed batch with any download in it answers 500. The ownership
branches also lost their `continue`, so another user's item is no longer
answered like a missing one (what #1507 added) and falls through to the
rest of the checks.

This puts #1507's ownership handling back and keeps #1508's skip of an
item that is no longer finished. The tests that came with both already
cover it: 12 of them fail on main right now and pass with this change.
Ruff, basedpyright and tests/core pass (1880 passed).

I flagged in #1508 that whichever of the two landed second needed a
rebase, and I should have rebased mine after #1507 merged instead of
leaving it for the merge. Sorry for the extra one.
2026-10-21 02:16:25 -04:00
dependabot[bot] c3608dd3c9 build(deps): bump publicsuffixlist from 1.1.0.20261010 to 1.1.0.20261017 (#1509)
Bumps [publicsuffixlist](https://github.com/ko-zu/psl) from
1.1.0.20261010 to 1.1.0.20261017.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/ko-zu/psl/commits">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=publicsuffixlist&package-manager=uv&previous-version=1.1.0.20261010&new-version=1.1.0.20261017)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-21 02:07:14 -04:00
splitsec2andCaliBrain f837506017 Merge commit from fork
A signed-in user picks the release fields of POST /api/releases/download, and a record
id with the "oceanofpdf:" prefix reached the provider without handles() or is_enabled().
The provider then fetched source_url, POSTed to the form action found on that page and
fetched the meta-refresh target, with no check on any of them.

The provider now refuses to run when it is switched off, and the book page, the form
action and every POST redirect hop must be on the configured mirror (same scheme, host
and port). The signed file link may sit on another host but must be http(s).

network.ensure_public_destination refuses a host that resolves to a loopback, private,
link-local or otherwise non-global address (IPv4-mapped IPv6 judged by its IPv4 address).
Hosts the operator configured as mirrors and names that do not resolve pass as before.
html_get_page and download_url call it on their first URL and check each redirect hop
through a response hook. The image cache uses the shared address check too.

Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-21 02:06:31 -04:00
splitsec2andCaliBrain cb72ce807c Merge commit from fork
A user could set any value for their own overridable settings through
PUT /api/users/me. DESTINATION and DESTINATION_AUDIOBOOK accepted any
string, so a download (including one an admin fulfilled for that user)
could be written to any directory the container can reach, and
get_destination created it on demand.

A user's own destination must now resolve inside the global one (with
{User} expanded on both sides). Absolute paths outside it and any ".."
segment are rejected at save time, and get_destination applies the same
check when the path is used, so a stored or hand-written value outside
the global destination is ignored with a warning and the global
destination is used instead. A relative value is taken relative to the
global destination.

Other self-service values are checked as well: select fields must use
one of their options, EMAIL_RECIPIENT must be a plain address (the same
check the orchestrator and the downloads tab use, now shared from
request_helpers), and Grimmory library and path ids must be non-negative
integers. Admin saves on a user's behalf are unchanged.

The self-service 400 response now carries a message line so the reason
reaches the user in the toast.

Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-21 02:05:05 -04:00
CaliBrain c269230ef3 fix: review regressions in metadata, notifications, activity redaction, search options and genDebug (#1510)
- **Open Library (#1451): keep the work unless the search matched a
translation.** Open Library shows an English edition whenever one
matches the query. So "Mistborn" returned the 2023 "Mistborn" reissue
(2023) instead of "The Final Empire" (2001), and "Children of Dune"
returned "Children of Dune (Dune Chronicles, Book 3)" (1987). The
matched edition's title, ISBNs, cover, language and year now win only
when the edition is in another language and the query doesn't name the
work's own title. Checked against live Open Library: "Children of Dune"
and "Mistborn" give the v1.4.0 results again, and "Der Weg der Könige"
and "Kinder des Nebels" still return the German editions.
- **Google Books (#1434): the ISBN cache decorator is back on
`search_by_isbn`.** It had moved to the new `search_paginated`. Failed
searches were cached as empty pages, and ISBN lookups lost their cache.
- **Notifications: Test notification shows the plugin's failure reason
again.** Apprise 2 delivers on its own worker threads, even for a single
service when that service has a deadline. `_AppriseLogCapture` filtered
records by thread id and dropped all of them, so the UI only said "json:
delivery failed". Apprise runs those workers in a copy of the caller's
context, so the capture now filters on a context variable. That still
keeps concurrent dispatches apart. `AppriseAsset(async_mode=False)`
would not fix this, because the sequential path also uses the worker
pool when a service has a deadline.
- **Activity: `activity_update` no longer sends the raw task id to
non-admins.** The owner's `user_<id>` room got the raw task id. For a
request-linked download that id can hold a private tracker's passkey. It
now goes through `viewer_download_id`, the same mapping `/api/status`
and `download_progress` use. The admins room still gets the raw id.
- **SearchBar (#1476): Escape and an outside click close the homepage's
inline options panel again,** as they did in v1.4.0.
- **genDebug.sh: packages are listed through `importlib.metadata`,**
since #1404 removed pip from the image. The script also now redacts:
  - `PROWLARR_MAM_ID`
- `user:pass@` credentials in URLs (proxies), in both the environment
and the config files
- notification route URLs, which carry their service's token (Telegram,
Discord and others)

- `make python-checks`, `make python-test`, `make frontend-checks` and
`make frontend-test` pass on top of current `main`.
- New tests cover:
  - Open Library edition selection
  - Google Books caching
- log capture against a real Apprise 2 delivery to a local server that
answers 500, plus a concurrent dispatch on another thread
  - the `activity_update` payload sent to each room
  - genDebug redaction and the package listing

  Each one fails on the old code.
- I checked the SearchBar fix in the running app, because the frontend
has no DOM test setup: Escape closes the panel, an outside click closes
it, and a click inside keeps it open.
- I ran the genDebug redaction under GNU sed (Debian image) and BSD sed.
The package listing ran in the pip-less image.
2026-10-21 01:58:41 -04:00
CaliBrain a00f3d28bf fix(slskd): refuse unsafe peer paths, keep queued downloads alive, report search outages (#1512)
Fixes four defects in the Soulseek (slskd)

A peer names its own files, and Shelfmark works out where slskd stored
one from the last folder and the file name. `remote_directory_name`
returned the whole directory when its last segment was empty. So
`../../../etc//passwd.epub` or `/abs/path//book.epub` resolved outside
the downloads folder, and Shelfmark imported whatever was there. For a
multi-file release it moved those files into staging (`STAGE_MOVE`).

- New `safe_remote_segments` refuses a name with an empty, `.` or `..`
segment (which covers absolute and UNC paths), a NUL, or a drive
anywhere but a Windows share root (`C:\Books\…`, which never reaches a
local path).
- Search (`iter_peer_files`, so `build_releases`) drops such files.
- `download` refuses them before anything is queued, in both modes. The
spec arrives with the queued release payload, so search filtering alone
is not enough.
- `local_path_for` also refuses a path that resolves outside the root
(`resolve()` + `is_relative_to`), for example through a symlinked
folder.

`_poll`, used when isolation is off and as the fallback for slskd <
0.26, never asked for an activity grace. A file "Queued, Remotely" sent
the same status and progress on every poll, so the orchestrator
cancelled it after 300s and `SLSKD_QUEUE_TIMEOUT_MINUTES` never applied.
It now requests, renews and releases the grace the same way isolated
mode does.

`search` caught every exception per query, so slskd being down or
rejecting the API key showed as "no releases". When no query gets an
answer it now raises `SourceUnavailableError`, as Prowlarr does, and the
error reaches the user. One failed query among answered ones is still
not an outage.

A retry reuses the task's folder, and slskd renames a new file when one
is already there. Files from a failed attempt therefore meant
`_folder_complete`'s exact count could never match again. Now:
- a failed or cancelled attempt removes its folder;
- a new attempt removes any finished files an earlier one left (for
example after a restart) before it queues the batch.

`tests/slskd/conftest.py` stubbed `flask_socketio` whenever it had not
been imported yet, even though it is installed. Running `pytest
tests/slskd tests/` therefore broke the Flask app tests in the same
worker (285 errors, also on 10710ab). It now stubs only when the module
is missing.

- 25 new regression tests. All of them fail on 10710ab.
- `make python-checks` passes.
- `uv run pytest tests/slskd tests/ -m "not integration and not e2e"`
passes: 4047 tests on e83bab9.
2026-10-21 01:58:13 -04:00
CaliBrain 49aeec97cd fix(download): stop deleting user data and losing completed downloads (#1511)
Fixes six defects. Each one breaks downloads or deletes user data, and
each has a regression test that fails on 10710ab and on 77b80eb (current
main).

- **Completed-path wait (#1464)**: `_wait_for_completed_path` only
returned a directory after two identical signatures of supported
formats.
- A directory holding only archives (a scene `book.rar` + `.nfo` +
`.sfv`) never got a signature and failed with "Completed download has no
stable supported files yet". Archives (`.zip`/`.rar`, via `is_archive`)
now count toward the signature, so post-processing extracts them again,
as in v1.4.0.
- With `DOWNLOAD_CLIENT_COMPLETED_PATH_TIMEOUT=0`, `max_attempts` is 1,
so every directory failed. One sample with book files or archives is now
accepted when no retry is possible.
- **Remove & Delete Files (#1401)**: `post_process_cleanup` called
`remove(id, delete_files=True)` on torrents matched by `find_existing`
that Shelfmark never added, deleting the user's seeding data.
`_cleanup_refs` now records `added_by_shelfmark`. A pre-existing torrent
(complete, or in progress and joined) is removed but keeps its files.
- **Cancelling an unstarted torrent (#1421)**:
`_remove_unstarted_torrent` deleted with files whenever `progress == 0`.
That included `DownloadStatus.error()`, which always reports 0, and
checking states that are re-verifying data already on disk. The torrent
must now be QUEUED, PAUSED or DOWNLOADING. rTorrent's
`remove(delete_files=True)` always returns False, so a new
`DownloadClient.can_delete_files` flag (False on rTorrent) makes it
remove without files instead.
- **Queue grace overwritten**: when a QUEUED torrent's progress rose on
the same poll, the 900 s queue grace was immediately replaced by a
shorter stall window, because the orchestrator keeps one deadline. The
stall window is now requested only when it is longer than what is left
of the queue grace.
- **`drop_ignored_files` (#1480)**: the suffix rule `w.endswith("/" +
rel)` dropped a kept root `Book.epub` when `Extras/Book.epub` was
skipped. Each skipped entry now drops at most one file: the exact path,
else the file sharing the most trailing components, else a unique
basename, else an AudiobookBay glued `"<folder> <file>"` name (the
fallback `match_plan_to_files` uses, matched on folder plus file so
chaptered `Book 2 01.mp3` picks the right folder). Ties drop nothing.
- **Email and BookLore outputs** ignored `task.ignored_files` and sent
every prepared file. Both now apply `drop_ignored_files` once after
`prepare_output_files`, and report "No book files found" if the user
skipped everything. It is applied in the outputs rather than in
`prepare` because the folder output already filters in
`transfer_book_files`, and filtering twice could match a kept file on
the second pass.

- `make python-checks`: ruff, ruff format, basedpyright (backend +
tests), vulture all pass.
- `uv run pytest tests/ -m "not integration and not e2e"`: 4054 passed
on the rebased branch.
- New tests run against unfixed 77b80eb and 10710ab: all 18 new
regression cases fail, and the 11 existing post-process-cleanup tests
also fail there because they now build the 4-tuple cleanup ref.
2026-10-21 01:56:19 -04:00
splitsec2andCaliBrain 520b6b16d0 fix(activity): Clear Completed leaves out an item that is no longer finished instead of failing the batch (#1508)
Clear Completed can fail outright with "Only terminal requests can be
dismissed". `dismiss-many` answers 409 and dismisses nothing when any
one request or download in the batch is not terminal. The list a user
clears from can be older than the server, so a request that was reopened
or retried since, or a download that started again, takes the whole
batch down with it. The earlier fix for pending requests (#1438) filters
on the client, which only helps when the list is current.

`dismiss-many` now skips such an item and carries on with the rest. The
response adds `skipped_item_keys` when something was left out, and
`count` is what was actually dismissed. A single `dismiss` of a
non-terminal item still answers 409.

I hit it with a request whose download had completed while the request
itself was still pending, but any reopen between the list and the click
does it.

This touches the same handler as #1507, so whichever lands second needs
a small rebase.

Tests: a batch with a finished and a reopened request dismisses the
finished one and reports the other, and a batch with a finished and a
running download does the same. Ruff, basedpyright and the backend suite
pass (3933 passed, e2e excluded).

Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-10-21 01:39:14 -04:00
splitsec2 61c7ad3c62 Merge commit from fork
* fix(torrent): check each redirect hop when fetching a torrent file

The torrent file fetch followed redirects by hand without looking at where a
hop pointed, so a download link could make the server request a loopback,
link-local or LAN address. Each hop (the initial URL and every redirect
Location) must now be http or https and resolve only to global addresses.
The configured Prowlarr/Newznab origin is exempt, as it usually lives on the
LAN. The API key still only goes to that origin.

* fix(socketio): only accept websocket handshakes from the app's own origin

The Socket.IO server allowed every origin. It now uses the same-origin check
python-engineio applies by default (Host, or X-Forwarded-Proto and
X-Forwarded-Host behind a proxy). SOCKETIO_ALLOWED_ORIGINS takes a comma
separated list of extra origins for proxies that change Host without
forwarding it.

* fix(custom-script): do not pass a file name that starts with a dash as the first argument

In relative path mode the script got the organized file's relative path as
its first argument, which many scripts read as an option when the name starts
with a dash. Such a name is now passed with a ./ prefix. Absolute mode is
unchanged.
2026-10-21 01:34:38 -04:00
splitsec2 8ec9db49da Merge commit from fork
The request line sent to the book bot comes from the request-supplied
source_id and was written to the socket as-is, so a line break in it sent
extra IRC commands as the operator's nick. IRCClient._send, the single
writer, now raises IRCError on any control character (CTCP 0x01 excepted),
the download handler rejects such a request line with a clear error before
connecting, and search refuses a query that contains one.
2026-10-20 23:40:33 -04:00