Compare commits

..
70 Commits
Author SHA1 Message Date
Anthony Stirling a9694e567a OPenAPI fixes 2025-09-04 16:34:27 +01:00
Ludy cb7471024b feat(common): add ChecksumUtils for MD5/SHA*/CRC32/Adler32 with Base64 and multi-algorithm support (#4261) 2025-09-04 15:38:28 +01:00
Balázs Szücs 74870615df Replace uses of Arrays.asList() with either List.of() or Collections.singletonList() (#4219) 2025-09-04 15:30:45 +01:00
Ludy 02d096d622 feat(security): add PFX alias for PKCS12; accept .crt/.cer/.der certs & .key keys; add certificate-signing tests (#4297) 2025-09-04 15:30:32 +01:00
LudyandCopilot 0d7649bee8 fix(ci:testdriver): conditionally run frontend tests based on file changes (#4064)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-04 15:11:09 +01:00
Ludy 0776ecc96b test(common): add dedicated unit tests for FileInfo and InputStreamTemplateResource (#4140) 2025-09-04 15:10:35 +01:00
Ludy 8113728d3d feat(database): make backup schedule configurable via system keys (#4251) 2025-09-04 15:02:31 +01:00
albanobattistella 528968bfe9 Update messages_it_IT.properties (#4285)
# Description of Changes

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-09-04 14:50:16 +01:00
dependabot[bot] 61b85a9273 build(deps): bump jakarta.mail:jakarta.mail-api from 2.1.3 to 2.1.4 (#4351)
Bumps
[jakarta.mail:jakarta.mail-api](https://github.com/jakartaee/mail-api)
from 2.1.3 to 2.1.4.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/jakartaee/mail-api/commit/0d13f04450f9590afa37761e04591526f47312e5"><code>0d13f04</code></a>
Prepare release jakarta.mail:jakarta.mail-api:2.1.4</li>
<li><a
href="https://github.com/jakartaee/mail-api/commit/958fb97ab1ebae1844629226fb06e27b05872c52"><code>958fb97</code></a>
services/jakarta.mail.Provider override not working <a
href="https://redirect.github.com/jakartaee/mail-api/issues/777">#777</a>
(<a
href="https://redirect.github.com/jakartaee/mail-api/issues/779">#779</a>)</li>
<li><a
href="https://github.com/jakartaee/mail-api/commit/3446c942412cb324ce448d65d6a805f3a6af599e"><code>3446c94</code></a>
services/jakarta.mail.Provider override not working <a
href="https://redirect.github.com/jakartaee/mail-api/issues/170">#170</a>
(<a
href="https://redirect.github.com/jakartaee/mail-api/issues/778">#778</a>)</li>
<li><a
href="https://github.com/jakartaee/mail-api/commit/892fae4ac7601976ee3270040a5b16d6349ce955"><code>892fae4</code></a>
Multipart performs blocking call in every instantiation <a
href="https://redirect.github.com/jakartaee/mail-api/issues/699">#699</a>
(<a
href="https://redirect.github.com/jakartaee/mail-api/issues/716">#716</a>)</li>
<li><a
href="https://github.com/jakartaee/mail-api/commit/666ec999d8931041d89eabf10d807e5262195f8f"><code>666ec99</code></a>
Bump rexml from 3.2.8 to 3.3.6 in /www</li>
<li><a
href="https://github.com/jakartaee/mail-api/commit/8eddc342b11436c2ab8a68ff5ab464e343edee99"><code>8eddc34</code></a>
Bump rexml from 3.2.5 to 3.2.8 in /www</li>
<li><a
href="https://github.com/jakartaee/mail-api/commit/1259b86a8c195db3337db9eff81214c357758c0e"><code>1259b86</code></a>
Bump nokogiri from 1.16.2 to 1.16.5 in /www</li>
<li><a
href="https://github.com/jakartaee/mail-api/commit/bf2bfc18c0d2b9b3f57417203c2a462a3a94a7de"><code>bf2bfc1</code></a>
Update README.md</li>
<li><a
href="https://github.com/jakartaee/mail-api/commit/038fa7038a26251bbf4a43ea577a5e7171d3a2e4"><code>038fa70</code></a>
Prepare next development cycle for 2.1.4-SNAPSHOT</li>
<li><a
href="https://github.com/jakartaee/mail-api/commit/1e520275467de4b1cc658fd83e1783c43d451b2e"><code>1e52027</code></a>
Prepare release jakarta.mail:jakarta.mail-api:2.1.3</li>
<li>See full diff in <a
href="https://github.com/jakartaee/mail-api/compare/2.1.3...2.1.4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=jakarta.mail:jakarta.mail-api&package-manager=gradle&previous-version=2.1.3&new-version=2.1.4)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-04 14:50:03 +01:00
Ludy c055f9456a feat(convert): PDF conversion with unoconvert fallback soffice (#4316)
# Description of Changes

- **What was changed**
- Reworked `ConvertOfficeController` to use a dedicated temporary
working directory per request and cleaned up with directory-level
deletion.
- Added detection for converter availability via `EndpointConfiguration`
to choose between **unoconvert** and a **soffice** headless fallback.
- Ensured safe filename handling (sanitization, extension checks,
lowercase normalization) and early validation errors for missing/invalid
filenames.
- Switched raw temp file writes to `Files.copy` / `Files.writeString`
with `StandardCopyOption.REPLACE_EXISTING`.
  - Implemented robust output handling:
    - Verified non-zero exit codes and null results.
    - Checked for missing/empty PDF outputs.
- Added fallback lookup for any produced `.pdf` within the work
directory if the expected name is not present.
  - Introduced `@Slf4j` logging; improved error and cleanup logging.
- Replaced ad-hoc temp cleanup with `FileUtils.deleteDirectory` for full
working-dir removal.
- Minor imports/cleanup: removed unused `Arrays`, added
`StandardCopyOption`, `FileUtils`, and related imports.

- **Why the change was made**
- Increase conversion reliability across environments where either
unoconvert or soffice may be available.
- Harden security and stability through strict input validation and
sanitized HTML processing.
- Prevent orphaned files/directories and ensure consistent cleanup to
reduce disk footprint and operational issues.
- Provide clearer operational signals (logging, explicit exceptions) for
easier troubleshooting.


---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-09-04 14:33:35 +01:00
Balázs SzücsandCopilot fe84b3ff15 feat: Add Lombok @Getter and @Setter annotations to reduce boilerplate code in multiple classes (#4321)
# Description of Changes

Update classes across the codebase to use Lombok's `@Getter` and
`@Setter` annotations, replacing manually written getter and setter
methods. This change streamlines the code, reduces boilerplate, and
improves maintainability.

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-04 14:29:55 +01:00
Ludy 9a213c4bf6 feat(misc): Add font color option for page numbers; improve alignment & robustness (#4334)
# Description of Changes

**What was changed**
- **API & backend**
- Added optional `fontColor` (hex, e.g. `#FF0000`) to
`AddPageNumbersRequest` with OpenAPI docs, default `#000000`.
- Decode hex color with safe fallback to black; apply via
`setNonStrokingColor`.
- Switched multiple `switch` statements to concise switch expressions
and used `Locale.ROOT` for case operations.
- Clamped `position` to `1..9` and reworked alignment using proper font
metrics (`ascent`/`descent`) for top/middle/bottom positioning.
  - Centralized filename base extraction; reduced repeated calls.  
  - Used try-with-resources for `PDPageContentStream`.
- **UI & i18n**
  - Added `addPageNumbers.fontColor` label (en_GB).  
- Introduced `<input type="color" id="fontColor" ...>` with live
background preview in the Add Page Numbers form.

**Why the change was made**
- Enable users to render page numbers in a chosen color (not just
black).
- Produce visually correct placement by accounting for font metrics
(baseline vs. optical middle).
- Improve resilience (locale-safe parsing, bounds checking) and code
clarity.

Closes #3839


[after.pdf](https://github.com/user-attachments/files/22064425/after.pdf)

[before.pdf](https://github.com/user-attachments/files/22064426/before.pdf)


---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-09-04 14:04:11 +01:00
Ludy a4a57cef92 fix(api): prevent MultipartFile binding errors in StampController (#4331)
# Description of Changes

- **What was changed**
- Added a Spring `@InitBinder` in `StampController` that registers a
`PropertyEditorSupport` for `MultipartFile` to safely handle text inputs
by setting the value to `null`.
- Replaced multiple `switch` statements with modern Java **switch
expressions**:
    - Margin selection (`customMargin`) now uses a concise expression.
- Font selection (`alphabet` → font resource path) rewritten as an
expression.
- Position calculations (`calculatePositionX` / `calculatePositionY`)
now return via switch expressions with `yield`.
- Minor readability and maintainability improvements without changing
public API or behavior (besides the binding fix).

- **Why the change was made**
- The `@InitBinder` prevents conversion/binding issues when Spring
attempts to map string form fields to `MultipartFile`, which could cause
exceptions or unexpected behavior in multipart/form-data requests.
- Using switch expressions reduces boilerplate, clarifies intent, and
makes the control flow safer and more maintainable.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-09-04 13:55:09 +01:00
stirlingbot[bot] 6f6f4a14dc 🌐 Sync Translations + Update README Progress Table (#4374)
### Description of Changes

This Pull Request was automatically generated to synchronize updates to
translation files and documentation. Below are the details of the
changes made:

#### **1. Synchronization of Translation Files**
- Updated translation files (`messages_*.properties`) to reflect changes
in the reference file `messages_en_GB.properties`.
- Ensured consistency and synchronization across all supported language
files.
- Highlighted any missing or incomplete translations.

#### **2. Update README.md**
- Generated the translation progress table in `README.md`.
- Added a summary of the current translation status for all supported
languages.
- Included up-to-date statistics on translation coverage.

#### **Why these changes are necessary**
- Keeps translation files aligned with the latest reference updates.
- Ensures the documentation reflects the current translation progress.

---

Auto-generated by [create-pull-request][1].

[1]: https://github.com/peter-evans/create-pull-request

---------

Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2025-09-04 12:56:18 +01:00
stirlingbot[bot] c50aadeb35 🤖 format everything with pre-commit by stirlingbot (#4185)
Auto-generated by [create-pull-request][1] with **stirlingbot**

[1]: https://github.com/peter-evans/create-pull-request

Signed-off-by: stirlingbot[bot] <stirlingbot[bot]@users.noreply.github.com>
Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2025-09-04 12:56:02 +01:00
Ludy 963b4ee69d refactor(ssrf): default enum MEDIUM prevents OFF=false (#4280)
# Description of Changes

- **What was changed**
  - **URL to PDF flow**
- Changed `ConvertWebsiteToPDF#urlToPdf` to return `ResponseEntity<?>`
and perform a redirect (`303 SEE_OTHER`) back to `/url-to-pdf` with an
`error` query param instead of throwing exceptions.
- Added alert rendering in `url-to-pdf.html` using `param.error` for
localized error display.
- Introduced new translation key `error.invalidUrlFormat` in
`messages_en_GB.properties`.
  - **Security / SSRF**
- Migrated `ApplicationProperties.System.UrlSecurity.level` from
`String` to `SsrfProtectionLevel` enum.
- Default now set to `SsrfProtectionLevel.MEDIUM` (`// MAX, MEDIUM,
OFF`).
- This avoids the issue where setting `OFF` returned `false` in
configuration parsing.
- Updated `SsrfProtectionService#parseProtectionLevel` accordingly
(using `level.name()`).
  - **Repo hygiene**
    - Added `**/LOCAL_APPDATA_FONTCONFIG_CACHE/**` to `.gitignore`.

- **Why the change was made**
- Provide user-friendly, localized error messages instead of exposing
internal exceptions on URL-to-PDF conversions.
- Ensure SSRF protection level parsing is type-safe and consistent—`OFF`
can now be set without yielding a misleading `false` state.
  - Prevent unwanted fontconfig cache files from being tracked in Git.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-09-04 12:39:37 +01:00
stirlingbot[bot] cd76f5e50a Update 3rd Party Licenses (#4278)
Auto-generated by stirlingbot[bot]

Signed-off-by: stirlingbot[bot] <stirlingbot[bot]@users.noreply.github.com>
Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2025-09-04 12:37:39 +01:00
stirlingbot[bot] 763d50ba8d 🌐 Sync Translations + Update README Progress Table (#4277)
### Description of Changes

This Pull Request was automatically generated to synchronize updates to
translation files and documentation. Below are the details of the
changes made:

#### **1. Synchronization of Translation Files**
- Updated translation files (`messages_*.properties`) to reflect changes
in the reference file `messages_en_GB.properties`.
- Ensured consistency and synchronization across all supported language
files.
- Highlighted any missing or incomplete translations.

#### **2. Update README.md**
- Generated the translation progress table in `README.md`.
- Added a summary of the current translation status for all supported
languages.
- Included up-to-date statistics on translation coverage.

#### **Why these changes are necessary**
- Keeps translation files aligned with the latest reference updates.
- Ensures the documentation reflects the current translation progress.

---

Auto-generated by [create-pull-request][1].

[1]: https://github.com/peter-evans/create-pull-request

---------

Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2025-09-04 12:37:07 +01:00
dependabot[bot] 4987932f60 build(deps): bump org.panteleyev.jpackageplugin from 1.7.3 to 1.7.5 (#4347)
Bumps org.panteleyev.jpackageplugin from 1.7.3 to 1.7.5.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.panteleyev.jpackageplugin&package-manager=gradle&previous-version=1.7.3&new-version=1.7.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-04 12:31:56 +01:00
dependabot[bot] 1036befaf1 build(deps): bump com.bucket4j:bucket4j_jdk17-core from 8.14.0 to 8.15.0 (#4279)
[//]: # (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
[com.bucket4j:bucket4j_jdk17-core](https://github.com/bucket4j/bucket4j)
from 8.14.0 to 8.15.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/bucket4j/bucket4j/releases">com.bucket4j:bucket4j_jdk17-core's
releases</a>.</em></p>
<blockquote>
<h2>8.15.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix typo in previous-releases link by <a
href="https://github.com/DominiQN"><code>@​DominiQN</code></a> in <a
href="https://redirect.github.com/bucket4j/bucket4j/pull/533">bucket4j/bucket4j#533</a></li>
<li>Fix typo in verbose-api docs by <a
href="https://github.com/cmg1411"><code>@​cmg1411</code></a> in <a
href="https://redirect.github.com/bucket4j/bucket4j/pull/540">bucket4j/bucket4j#540</a></li>
<li>Fix comment in redisson.adoc by <a
href="https://github.com/K-jun98"><code>@​K-jun98</code></a> in <a
href="https://redirect.github.com/bucket4j/bucket4j/pull/541">bucket4j/bucket4j#541</a></li>
<li>Add valid example using Redisson library by <a
href="https://github.com/JoshWein"><code>@​JoshWein</code></a> in <a
href="https://redirect.github.com/bucket4j/bucket4j/pull/542">bucket4j/bucket4j#542</a></li>
<li>MongoDB backend by <a
href="https://github.com/granikartem"><code>@​granikartem</code></a> in
<a
href="https://redirect.github.com/bucket4j/bucket4j/pull/549">bucket4j/bucket4j#549</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/DominiQN"><code>@​DominiQN</code></a>
made their first contribution in <a
href="https://redirect.github.com/bucket4j/bucket4j/pull/533">bucket4j/bucket4j#533</a></li>
<li><a href="https://github.com/cmg1411"><code>@​cmg1411</code></a> made
their first contribution in <a
href="https://redirect.github.com/bucket4j/bucket4j/pull/540">bucket4j/bucket4j#540</a></li>
<li><a href="https://github.com/K-jun98"><code>@​K-jun98</code></a> made
their first contribution in <a
href="https://redirect.github.com/bucket4j/bucket4j/pull/541">bucket4j/bucket4j#541</a></li>
<li><a href="https://github.com/JoshWein"><code>@​JoshWein</code></a>
made their first contribution in <a
href="https://redirect.github.com/bucket4j/bucket4j/pull/542">bucket4j/bucket4j#542</a></li>
<li><a
href="https://github.com/granikartem"><code>@​granikartem</code></a>
made their first contribution in <a
href="https://redirect.github.com/bucket4j/bucket4j/pull/549">bucket4j/bucket4j#549</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/bucket4j/bucket4j/compare/8.14.0...8.15.0">https://github.com/bucket4j/bucket4j/compare/8.14.0...8.15.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bucket4j/bucket4j/commit/1ecc3152b8c9383d12e37aae1e6a431dbac9baa1"><code>1ecc315</code></a>
Documentation for release 8.15.0</li>
<li><a
href="https://github.com/bucket4j/bucket4j/commit/0d257fd2f4f9ff871268feef50c7f40a7b8bb486"><code>0d257fd</code></a>
Documentation for release 8.15.0</li>
<li><a
href="https://github.com/bucket4j/bucket4j/commit/621f5d58043cad215fae598e432c45d6ebaa32e0"><code>621f5d5</code></a>
Documentation for release 8.15.0</li>
<li><a
href="https://github.com/bucket4j/bucket4j/commit/2930d8388b6168f8056ffa9e0ac6a72a8efa230d"><code>2930d83</code></a>
<a
href="https://redirect.github.com/bucket4j/bucket4j/issues/549">#549</a>
documentations</li>
<li><a
href="https://github.com/bucket4j/bucket4j/commit/9b7f66a80f69b48dd2b7cc79699d651eb5eaba20"><code>9b7f66a</code></a>
Changes according to the OSSRH Sunset <a
href="https://central.sonatype.org/pages/ossr">https://central.sonatype.org/pages/ossr</a>...</li>
<li><a
href="https://github.com/bucket4j/bucket4j/commit/a9dae860eae3298cdd223cb06ede4669222463b5"><code>a9dae86</code></a>
<a
href="https://redirect.github.com/bucket4j/bucket4j/issues/549">#549</a>
do not insist on specific the mongo-driver versions</li>
<li><a
href="https://github.com/bucket4j/bucket4j/commit/4c4f1b9f7a0fd1987690ac728214bc06bc9332f1"><code>4c4f1b9</code></a>
<a
href="https://redirect.github.com/bucket4j/bucket4j/issues/549">#549</a>
add project names</li>
<li><a
href="https://github.com/bucket4j/bucket4j/commit/3e024b0fb0d5d7c0c9f7dbee948f64ac9bda69ed"><code>3e024b0</code></a>
<a
href="https://redirect.github.com/bucket4j/bucket4j/issues/549">#549</a>
add license</li>
<li><a
href="https://github.com/bucket4j/bucket4j/commit/70e9cf58f93d3641d91a4428bb5eb9c25c7a9d3b"><code>70e9cf5</code></a>
<a
href="https://redirect.github.com/bucket4j/bucket4j/issues/549">#549</a>
fix modular-name</li>
<li><a
href="https://github.com/bucket4j/bucket4j/commit/1cbc7e1f3e70de94ec1ff4d6deea7d5b1bf15ea4"><code>1cbc7e1</code></a>
<a
href="https://redirect.github.com/bucket4j/bucket4j/issues/549">#549</a>
fix maven configuration</li>
<li>Additional commits viewable in <a
href="https://github.com/bucket4j/bucket4j/compare/8.14.0...8.15.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=com.bucket4j:bucket4j_jdk17-core&package-manager=gradle&previous-version=8.14.0&new-version=8.15.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-04 12:29:40 +01:00
dependabot[bot] 8a4acd4c98 build(deps): bump org.sonarqube from 6.2.0.5505 to 6.3.1.5724 (#4352)
Bumps org.sonarqube from 6.2.0.5505 to 6.3.1.5724.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.sonarqube&package-manager=gradle&previous-version=6.2.0.5505&new-version=6.3.1.5724)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-04 12:29:30 +01:00
dependabot[bot] f93d8511e8 build(deps): bump actions/dependency-review-action from 4.7.2 to 4.7.3 (#4353)
[//]: # (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
[actions/dependency-review-action](https://github.com/actions/dependency-review-action)
from 4.7.2 to 4.7.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/dependency-review-action/releases">actions/dependency-review-action's
releases</a>.</em></p>
<blockquote>
<h2>4.7.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Add explicit permissions to workflow files by <a
href="https://github.com/AshelyTC"><code>@​AshelyTC</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/966">actions/dependency-review-action#966</a></li>
<li>Claire153/fix spamming mentioned issue by <a
href="https://github.com/claire153"><code>@​claire153</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/974">actions/dependency-review-action#974</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/dependency-review-action/compare/v4...v4.7.3">https://github.com/actions/dependency-review-action/compare/v4...v4.7.3</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/dependency-review-action/commit/595b5aeba73380359d98a5e087f648dbb0edce1b"><code>595b5ae</code></a>
Update package version (<a
href="https://redirect.github.com/actions/dependency-review-action/issues/975">#975</a>)</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/fc5fd661aa443a25c657922b187812d85d3c6fa7"><code>fc5fd66</code></a>
Claire153/fix spamming mentioned issue (<a
href="https://redirect.github.com/actions/dependency-review-action/issues/974">#974</a>)</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/d38d1a4f40f1e9fd802865455d695d0ae924edee"><code>d38d1a4</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/dependency-review-action/issues/965">#965</a>
from actions/dependabot/npm_and_yarn/multi-c22e25d29b</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/8d420b827cac87791e1303cb1b01d3447e0bb8df"><code>8d420b8</code></a>
Merge branch 'main' into dependabot/npm_and_yarn/multi-c22e25d29b</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/bde01290d367cf6ae7232580700fcca870e35a80"><code>bde0129</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/dependency-review-action/issues/966">#966</a>
from actions/ashelytc/add-permissions</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/ab524903e88a228b6df0ab1dc878a34aebc28b70"><code>ab52490</code></a>
remove ruby</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/ef00a0afbb540db022eb79fc3aea57b5603d7a47"><code>ef00a0a</code></a>
add permissions to workflows</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/74c8179d39388ccd6863b1a230d2cd3e1d0de71d"><code>74c8179</code></a>
Bump brace-expansion</li>
<li>See full diff in <a
href="https://github.com/actions/dependency-review-action/compare/bc41886e18ea39df68b1b1245f4184881938e050...595b5aeba73380359d98a5e087f648dbb0edce1b">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/dependency-review-action&package-manager=github_actions&previous-version=4.7.2&new-version=4.7.3)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-04 12:28:46 +01:00
dependabot[bot] 54c7b0e689 build(deps): bump actions/setup-java from 4.7.1 to 5.0.0 (#4269)
Bumps [actions/setup-java](https://github.com/actions/setup-java) from
4.7.1 to 5.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-java/releases">actions/setup-java's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<h3>Breaking Changes</h3>
<ul>
<li>Upgrade to node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/setup-java/pull/888">actions/setup-java#888</a></li>
</ul>
<p>Make sure your runner is updated to this version or newer to use this
release. v2.327.1 <a
href="https://github.com/actions/runner/releases/tag/v2.327.1">Release
Notes</a></p>
<h3>Dependency Upgrades</h3>
<ul>
<li>Upgrade Publish Immutable Action by <a
href="https://github.com/HarithaVattikuti"><code>@​HarithaVattikuti</code></a>
in <a
href="https://redirect.github.com/actions/setup-java/pull/798">actions/setup-java#798</a></li>
<li>Upgrade eslint-plugin-jest from 27.9.0 to 28.11.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-java/pull/730">actions/setup-java#730</a></li>
<li>Upgrade undici from 5.28.5 to 5.29.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-java/pull/833">actions/setup-java#833</a></li>
<li>Upgrade form-data to bring in fix for critical vulnerability by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-java/pull/887">actions/setup-java#887</a></li>
<li>Upgrade actions/checkout from 4 to 5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-java/pull/896">actions/setup-java#896</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Prevent default installation of JetBrains pre-releases by <a
href="https://github.com/priyagupta108"><code>@​priyagupta108</code></a>
in <a
href="https://redirect.github.com/actions/setup-java/pull/859">actions/setup-java#859</a></li>
<li>Improve Error Handling for Setup-Java Action to Help Debug
Intermittent Failures by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-java/pull/848">actions/setup-java#848</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-java/pull/848">actions/setup-java#848</a></li>
<li><a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-java/pull/888">actions/setup-java#888</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-java/compare/v4...v5.0.0">https://github.com/actions/setup-java/compare/v4...v5.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-java/commit/dded0888837ed1f317902acf8a20df0ad188d165"><code>dded088</code></a>
Bump actions/checkout from 4 to 5 (<a
href="https://redirect.github.com/actions/setup-java/issues/896">#896</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/0913e9a06eb8b69c62db76aa61f580c2b3a5b4e0"><code>0913e9a</code></a>
Upgrade to node 24 (<a
href="https://redirect.github.com/actions/setup-java/issues/888">#888</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/e9343db97e09d87a3c50e544105d99fe912c204b"><code>e9343db</code></a>
Bumps form-data (<a
href="https://redirect.github.com/actions/setup-java/issues/887">#887</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/ae2b61dbc685e60e4427b2e8ed4f0135c6ea8597"><code>ae2b61d</code></a>
Bump undici from 5.28.5 to 5.29.0 (<a
href="https://redirect.github.com/actions/setup-java/issues/833">#833</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/c190c18febcf6c040d80b10ea201a05a2c320263"><code>c190c18</code></a>
Bump eslint-plugin-jest from 27.9.0 to 29.0.1 (<a
href="https://redirect.github.com/actions/setup-java/issues/730">#730</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/67aec007b3fcabe15ca665bfccc1e255dd52e30d"><code>67aec00</code></a>
Fix: prevent default installation of JetBrains pre-releases (<a
href="https://redirect.github.com/actions/setup-java/issues/859">#859</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/ebb356cc4e59bcf94f518203228485f5d40e4b58"><code>ebb356c</code></a>
Improve Error Handling for Setup-Java Action to Help Debug Intermittent
Failu...</li>
<li><a
href="https://github.com/actions/setup-java/commit/f4f1212c880fdec8162ea9a6493f4495191887b4"><code>f4f1212</code></a>
Update publish-immutable-actions.yml (<a
href="https://redirect.github.com/actions/setup-java/issues/798">#798</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/setup-java/compare/c5195efecf7bdfc987ee8bae7a71cb8b11521c00...dded0888837ed1f317902acf8a20df0ad188d165">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-java&package-manager=github_actions&previous-version=4.7.1&new-version=5.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-04 12:28:22 +01:00
dependabot[bot] 58ca41e5c5 build(deps): bump actions/checkout from 4.3.0 to 5.0.0 (#4194)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.3.0
to 5.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
<li>Prepare v5.0.0 release by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2238">actions/checkout#2238</a></li>
</ul>
<h2>⚠️ Minimum Compatible Runner Version</h2>
<p><strong>v2.327.1</strong><br />
<a
href="https://github.com/actions/runner/releases/tag/v2.327.1">Release
Notes</a></p>
<p>Make sure your runner is updated to this version or newer to use this
release.</p>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4...v5.0.0">https://github.com/actions/checkout/compare/v4...v5.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>V5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>V4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>v4.2.0</h2>
<ul>
<li>Add Ref and Commit outputs by <a
href="https://github.com/lucacome"><code>@​lucacome</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li>
<li>Dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>- <a
href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>,
<a
href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li>
</ul>
<h2>v4.1.7</h2>
<ul>
<li>Bump the minor-npm-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li>
<li>Check out other refs/* by commit by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li>
<li>Pin actions/checkout's own workflows to a known, good, stable
version. by <a href="https://github.com/jww3"><code>@​jww3</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1776">actions/checkout#1776</a></li>
</ul>
<h2>v4.1.6</h2>
<ul>
<li>Check platform to set archive extension appropriately by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1732">actions/checkout#1732</a></li>
</ul>
<h2>v4.1.5</h2>
<ul>
<li>Update NPM dependencies by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1703">actions/checkout#1703</a></li>
<li>Bump github/codeql-action from 2 to 3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1694">actions/checkout#1694</a></li>
<li>Bump actions/setup-node from 1 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1696">actions/checkout#1696</a></li>
<li>Bump actions/upload-artifact from 2 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1695">actions/checkout#1695</a></li>
<li>README: Suggest <code>user.email</code> to be
<code>41898282+github-actions[bot]@users.noreply.github.com</code> by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1707">actions/checkout#1707</a></li>
</ul>
<h2>v4.1.4</h2>
<ul>
<li>Disable <code>extensions.worktreeConfig</code> when disabling
<code>sparse-checkout</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1692">actions/checkout#1692</a></li>
<li>Add dependabot config by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1688">actions/checkout#1688</a></li>
<li>Bump the minor-actions-dependencies group with 2 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1693">actions/checkout#1693</a></li>
<li>Bump word-wrap from 1.2.3 to 1.2.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1643">actions/checkout#1643</a></li>
</ul>
<h2>v4.1.3</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/checkout/commit/08c6903cd8c0fde910a37f88322edcfb5dd907a8"><code>08c6903</code></a>
Prepare v5.0.0 release (<a
href="https://redirect.github.com/actions/checkout/issues/2238">#2238</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/9f265659d3bb64ab1440b03b12f4d47a24320917"><code>9f26565</code></a>
Update actions checkout to use node 24 (<a
href="https://redirect.github.com/actions/checkout/issues/2226">#2226</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/checkout/compare/08eba0b27e820071cde6df949e0beb9ba4906955...08c6903cd8c0fde910a37f88322edcfb5dd907a8">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.3.0&new-version=5.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-04 12:27:59 +01:00
Anthony Stirling bf90f4b1da feat: add annotation option to PDF to image (#4365)
## Summary
- add optional flag to include PDF annotations when converting to images
- expose annotation option via API model and UI checkbox
- add translation for annotation option

## Testing
- `./gradlew spotlessApply`
- `./gradlew build`


------
https://chatgpt.com/codex/tasks/task_b_68b7fa1d5a1c83288342244a0ec85e9d
2025-09-04 12:21:29 +01:00
dependabot[bot] 7e276e8406 build(deps): bump github/codeql-action from 3.29.11 to 3.30.0 (#4355)
Bumps [github/codeql-action](https://github.com/github/codeql-action)
from 3.29.11 to 3.30.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action's
releases</a>.</em></p>
<blockquote>
<h2>v3.30.0</h2>
<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>3.30.0 - 01 Sep 2025</h2>
<p>No user facing changes.</p>
<p>See the full <a
href="https://github.com/github/codeql-action/blob/v3.30.0/CHANGELOG.md">CHANGELOG.md</a>
for more information.</p>
</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'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>3.30.0 - 01 Sep 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.11 - 21 Aug 2025</h2>
<ul>
<li>Update default CodeQL bundle version to 2.22.4. <a
href="https://redirect.github.com/github/codeql-action/pull/3044">#3044</a></li>
</ul>
<h2>3.29.10 - 18 Aug 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.9 - 12 Aug 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.8 - 08 Aug 2025</h2>
<ul>
<li>Fix an issue where the Action would autodetect unsupported languages
such as HTML. <a
href="https://redirect.github.com/github/codeql-action/pull/3015">#3015</a></li>
</ul>
<h2>3.29.7 - 07 Aug 2025</h2>
<p>This release rolls back 3.29.6 to address issues with language
autodetection. It is identical to 3.29.5.</p>
<h2>3.29.6 - 07 Aug 2025</h2>
<ul>
<li>The <code>cleanup-level</code> input to the <code>analyze</code>
Action is now deprecated. The CodeQL Action has written a limited amount
of intermediate results to the database since version 2.2.5, and now
automatically manages cleanup. <a
href="https://redirect.github.com/github/codeql-action/pull/2999">#2999</a></li>
<li>Update default CodeQL bundle version to 2.22.3. <a
href="https://redirect.github.com/github/codeql-action/pull/3000">#3000</a></li>
</ul>
<h2>3.29.5 - 29 Jul 2025</h2>
<ul>
<li>Update default CodeQL bundle version to 2.22.2. <a
href="https://redirect.github.com/github/codeql-action/pull/2986">#2986</a></li>
</ul>
<h2>3.29.4 - 23 Jul 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.3 - 21 Jul 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.2 - 30 Jun 2025</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d"><code>2d92b76</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3067">#3067</a>
from github/update-v3.30.0-92eada825</li>
<li><a
href="https://github.com/github/codeql-action/commit/390daafd7d971cca449e6aa45656ac85ca1d29fd"><code>390daaf</code></a>
Update changelog for v3.30.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/92eada825a77b70d62c71adc29a0a9fe75c21bf5"><code>92eada8</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3033">#3033</a>
from github/mbg/ci/rollback-release</li>
<li><a
href="https://github.com/github/codeql-action/commit/872a6a41e95ca66b6ce89dac89c1fbb97b171c89"><code>872a6a4</code></a>
Add <code>pull-requests: write</code> permission</li>
<li><a
href="https://github.com/github/codeql-action/commit/9389ce0cc4cf11345ec3a2a7a61fc790feb44165"><code>9389ce0</code></a>
Merge remote-tracking branch 'origin/main' into
mbg/ci/rollback-release</li>
<li><a
href="https://github.com/github/codeql-action/commit/02ab253bd299d261d00cdf8a9bca38fea2697d50"><code>02ab253</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3054">#3054</a>
from github/henrymercer/bundle</li>
<li><a
href="https://github.com/github/codeql-action/commit/b06d32585026d970f28d3f3604a67ddf4c314f9e"><code>b06d325</code></a>
Add draft release URL to job summary</li>
<li><a
href="https://github.com/github/codeql-action/commit/43d629cdfd9a8e4ac201aeb0d9330b2eaf0f8699"><code>43d629c</code></a>
Use <code>argparse</code> in <code>rollback_changelog.py</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/8f01f5d4296c6c45c71748648c333daa34454bb2"><code>8f01f5d</code></a>
Apply suggestions from code review</li>
<li><a
href="https://github.com/github/codeql-action/commit/3e493e72f755ad15a0ff97b25da2e232b3cb4f3f"><code>3e493e7</code></a>
Remove <code>removeNPMAbsolutePaths</code></li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/3c3833e0f8c1c83d449a7478aa59c036a9165498...2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=3.29.11&new-version=3.30.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-04 12:04:22 +01:00
dependabot[bot] 18e2078b8b build(deps): bump org.springdoc:springdoc-openapi-starter-webmvc-ui from 2.8.11 to 2.8.12 (#4356)
Bumps
[org.springdoc:springdoc-openapi-starter-webmvc-ui](https://github.com/springdoc/springdoc-openapi)
from 2.8.11 to 2.8.12.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/springdoc/springdoc-openapi/releases">org.springdoc:springdoc-openapi-starter-webmvc-ui's
releases</a>.</em></p>
<blockquote>
<h2>springdoc-openapi v2.8.12 released!</h2>
<h3>Changed</h3>
<ul>
<li>Upgrade swagger-ui to v5.28.0</li>
<li>Upgrade commons-lang3 to v3.18.0</li>
</ul>
<h3>Fixed</h3>
<ul>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3073">#3073</a>
- Duplicate key class Parameter when documenting two GET methods with
same path and PathVariable.</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3071">#3071</a>
- <a
href="https://github.com/io"><code>@​io</code></a>.swagger.v3.oas.annotations.parameters.RequestBody
does not work well with <a
href="https://github.com/RequestPart"><code>@​RequestPart</code></a></li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3066">#3066</a>
- Parameter is now required after upgrading to springdoc-openapi
2.8.10</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/springdoc/springdoc-openapi/compare/v2.8.11...v2.8.12">https://github.com/springdoc/springdoc-openapi/compare/v2.8.11...v2.8.12</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/springdoc/springdoc-openapi/blob/main/CHANGELOG.md">org.springdoc:springdoc-openapi-starter-webmvc-ui's
changelog</a>.</em></p>
<blockquote>
<h2>[2.8.12] - 2025-09-01</h2>
<h3>Changed</h3>
<ul>
<li>Upgrade swagger-ui to v5.28.0</li>
<li>Upgrade commons-lang3 to v3.18.0</li>
</ul>
<h3>Fixed</h3>
<ul>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3073">#3073</a>
- Duplicate key class Parameter when documenting two GET methods with
same path and PathVariable.</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3071">#3071</a>
- <a
href="https://github.com/io"><code>@​io</code></a>.swagger.v3.oas.annotations.parameters.RequestBody
does not work well with <a
href="https://github.com/RequestPart"><code>@​RequestPart</code></a></li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3066">#3066</a>
- Parameter is now required after upgrading to springdoc-openapi
2.8.10</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/493cc68492922bbbc3d123bace668d1402be93b5"><code>493cc68</code></a>
[maven-release-plugin] prepare release v2.8.12</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/8ef9eb819961a2effaaaa4358e911b9317372033"><code>8ef9eb8</code></a>
CHANGELOG.md update</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/bc4ba682eb106596580a5d994ecea95c0c605769"><code>bc4ba68</code></a>
upgrade commons-lang3 to v3.18.0</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/8741823941a6ec61f65024c3acd7a03fb5d8cd0d"><code>8741823</code></a>
upgrade swagger-ui to v5.28.0</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/8d85e0e445afc4109e32a697c025ae44ffded884"><code>8d85e0e</code></a>
Duplicate key class Parameter when documenting two GET methods with same
path...</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/4d505d62ddb39496243db7c8fd94e513e1baa11e"><code>4d505d6</code></a>
<a
href="https://github.com/io"><code>@​io</code></a>.swagger.v3.oas.annotations.parameters.RequestBody
does not work well with...</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/3190ae2c7fc8320ad9e708e655e53c0bd7cfc754"><code>3190ae2</code></a>
Parameter is now required after upgrading to springdoc-openapi 2.8.10.
Fixes ...</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/74dcd4f8459e824c687ef450b8be7656c008cd20"><code>74dcd4f</code></a>
[maven-release-plugin] prepare for next development iteration</li>
<li>See full diff in <a
href="https://github.com/springdoc/springdoc-openapi/compare/v2.8.11...v2.8.12">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.springdoc:springdoc-openapi-starter-webmvc-ui&package-manager=gradle&previous-version=2.8.11&new-version=2.8.12)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-04 12:03:59 +01:00
Adityarup LahaandAnthony Stirling 4b6ac87419 PdfContainer: zero-pad numeric suffix in nameAndArchiveFiles (#4265)
# Description of Changes

Zero pad the numeric suffix in `PdfContainer.nameAndArchiveFiles` to
close #4263.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2025-08-28 19:48:06 +00:00
dependabot[bot]andDario Ghunney Ware 1d527db305 build(deps): bump jwtVersion from 0.12.7 to 0.13.0 (#4270)
Bumps `jwtVersion` from 0.12.7 to 0.13.0.
Updates `io.jsonwebtoken:jjwt-api` from 0.12.7 to 0.13.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jwtk/jjwt/releases">io.jsonwebtoken:jjwt-api's
releases</a>.</em></p>
<blockquote>
<h2>0.13.0</h2>
<p><strong>This is the last minor JJWT release branch that will support
Java 7</strong>.</p>
<p>Any necessary emergency bug fixes will be fixed in subsequent
<code>0.13.x</code> patch releases, but all new development, including
<a
href="https://github.com/jwtk/jjwt/issues?q=is%3Aissue%20label%3Ajdk8">Java
8 compatible changes</a>, will be in the next minor
(<code>0.14.0</code>) release.</p>
<p><strong>All future JJWT major and minor versions (
<code>0.14.0</code> and later) will require Java 8 or
later.</strong></p>
<h2>What's Changed</h2>
<p>This release contains a single change:</p>
<ul>
<li>The previously private <code>JacksonDeserializer(ObjectMapper
objectMapper, Map&lt;String, Class&lt;?&gt;&gt; claimTypeMap)</code>
constructor is now <code>public</code> for those that want register a
claims type converter on their own specified <code>ObjectMapper</code>
instance. Thank you to <a
href="https://github.com/kesrishubham2510"><code>@​kesrishubham2510</code></a>
for PR <a
href="https://redirect.github.com/jwtk/jjwt/issues/972">#972</a>. See <a
href="https://redirect.github.com/jwtk/jjwt/issues/914">Issue
914</a>.</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/jwtk/jjwt/compare/0.12.7...0.13.0">https://github.com/jwtk/jjwt/compare/0.12.7...0.13.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/jwtk/jjwt/blob/master/CHANGELOG.md">io.jsonwebtoken:jjwt-api's
changelog</a>.</em></p>
<blockquote>
<h3>0.13.0</h3>
<p>This is the last minor JJWT release branch that will support Java 7.
Any necessary emergency bug fixes will be fixed in subsequent
<code>0.13.x</code> patch releases, but all new development, including
Java 8 compatible changes, will be in the next minor
(<code>0.14.0</code>) release.</p>
<p><strong>All future JJWT major and minor versions (
<code>0.14.0</code> and later) will require Java 8 or
later.</strong></p>
<p>This <code>0.13.0</code> minor release has only one change:</p>
<ul>
<li>The previously private <code>JacksonDeserializer(ObjectMapper
objectMapper, Map&lt;String, Class&lt;?&gt;&gt; claimTypeMap)</code>
constructor is now <code>public</code> for those that want register a
claims
type converter on their own specified <code>ObjectMapper</code>
instance. See <a
href="https://redirect.github.com/jwtk/jjwt/issues/914">Issue
914</a>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/jwtk/jjwt/commit/a757addce04f6b6d8086beeee8dafcf670550a5b"><code>a757add</code></a>
[maven-release-plugin] prepare release 0.13.0</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/e357463c59cf62c1f70503ac0102d10efcdfc37d"><code>e357463</code></a>
Preparing for the 0.13.0 release.</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/b6f8cb82a9c2e9817d842bfe72d2c8fb03124342"><code>b6f8cb8</code></a>
Made constructor public to allow users their own objectMapper instance
(<a
href="https://redirect.github.com/jwtk/jjwt/issues/972">#972</a>)</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/03f088a4eb774bae2403c428aa885a12d3afde14"><code>03f088a</code></a>
Bumping development version to 0.13.0-SNAPSHOT (<a
href="https://redirect.github.com/jwtk/jjwt/issues/1014">#1014</a>)</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/3f2697f854bedebe63e9eddb8c596f76086d11ca"><code>3f2697f</code></a>
Release 0.12.7 (<a
href="https://redirect.github.com/jwtk/jjwt/issues/1012">#1012</a>)</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/a0a123e848fc25a7920bcbd84615f639c4cc098a"><code>a0a123e</code></a>
PR <a
href="https://redirect.github.com/jwtk/jjwt/issues/917">#917</a></li>
<li>See full diff in <a
href="https://github.com/jwtk/jjwt/compare/0.12.7...0.13.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `io.jsonwebtoken:jjwt-impl` from 0.12.7 to 0.13.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jwtk/jjwt/releases">io.jsonwebtoken:jjwt-impl's
releases</a>.</em></p>
<blockquote>
<h2>0.13.0</h2>
<p><strong>This is the last minor JJWT release branch that will support
Java 7</strong>.</p>
<p>Any necessary emergency bug fixes will be fixed in subsequent
<code>0.13.x</code> patch releases, but all new development, including
<a
href="https://github.com/jwtk/jjwt/issues?q=is%3Aissue%20label%3Ajdk8">Java
8 compatible changes</a>, will be in the next minor
(<code>0.14.0</code>) release.</p>
<p><strong>All future JJWT major and minor versions (
<code>0.14.0</code> and later) will require Java 8 or
later.</strong></p>
<h2>What's Changed</h2>
<p>This release contains a single change:</p>
<ul>
<li>The previously private <code>JacksonDeserializer(ObjectMapper
objectMapper, Map&lt;String, Class&lt;?&gt;&gt; claimTypeMap)</code>
constructor is now <code>public</code> for those that want register a
claims type converter on their own specified <code>ObjectMapper</code>
instance. Thank you to <a
href="https://github.com/kesrishubham2510"><code>@​kesrishubham2510</code></a>
for PR <a
href="https://redirect.github.com/jwtk/jjwt/issues/972">#972</a>. See <a
href="https://redirect.github.com/jwtk/jjwt/issues/914">Issue
914</a>.</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/jwtk/jjwt/compare/0.12.7...0.13.0">https://github.com/jwtk/jjwt/compare/0.12.7...0.13.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/jwtk/jjwt/blob/master/CHANGELOG.md">io.jsonwebtoken:jjwt-impl's
changelog</a>.</em></p>
<blockquote>
<h3>0.13.0</h3>
<p>This is the last minor JJWT release branch that will support Java 7.
Any necessary emergency bug fixes will be fixed in subsequent
<code>0.13.x</code> patch releases, but all new development, including
Java 8 compatible changes, will be in the next minor
(<code>0.14.0</code>) release.</p>
<p><strong>All future JJWT major and minor versions (
<code>0.14.0</code> and later) will require Java 8 or
later.</strong></p>
<p>This <code>0.13.0</code> minor release has only one change:</p>
<ul>
<li>The previously private <code>JacksonDeserializer(ObjectMapper
objectMapper, Map&lt;String, Class&lt;?&gt;&gt; claimTypeMap)</code>
constructor is now <code>public</code> for those that want register a
claims
type converter on their own specified <code>ObjectMapper</code>
instance. See <a
href="https://redirect.github.com/jwtk/jjwt/issues/914">Issue
914</a>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/jwtk/jjwt/commit/a757addce04f6b6d8086beeee8dafcf670550a5b"><code>a757add</code></a>
[maven-release-plugin] prepare release 0.13.0</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/e357463c59cf62c1f70503ac0102d10efcdfc37d"><code>e357463</code></a>
Preparing for the 0.13.0 release.</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/b6f8cb82a9c2e9817d842bfe72d2c8fb03124342"><code>b6f8cb8</code></a>
Made constructor public to allow users their own objectMapper instance
(<a
href="https://redirect.github.com/jwtk/jjwt/issues/972">#972</a>)</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/03f088a4eb774bae2403c428aa885a12d3afde14"><code>03f088a</code></a>
Bumping development version to 0.13.0-SNAPSHOT (<a
href="https://redirect.github.com/jwtk/jjwt/issues/1014">#1014</a>)</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/3f2697f854bedebe63e9eddb8c596f76086d11ca"><code>3f2697f</code></a>
Release 0.12.7 (<a
href="https://redirect.github.com/jwtk/jjwt/issues/1012">#1012</a>)</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/a0a123e848fc25a7920bcbd84615f639c4cc098a"><code>a0a123e</code></a>
PR <a
href="https://redirect.github.com/jwtk/jjwt/issues/917">#917</a></li>
<li>See full diff in <a
href="https://github.com/jwtk/jjwt/compare/0.12.7...0.13.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `io.jsonwebtoken:jjwt-jackson` from 0.12.7 to 0.13.0


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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
Co-authored-by: Dario Ghunney Ware <dariogware@gmail.com>
2025-08-27 10:28:08 +00:00
LudyandCopilot 3af93f0adb feat(database,Jwt): relocate backups and Jwt-keys to config/backup and add Enterprise cleanup endpoints (#4225)
# Description of Changes

- **What was changed**
  - Centralized installation paths:
- Introduced `BACKUP_PATH`, `BACKUP_DB_PATH`, and
`BACKUP_PRIVATE_KEY_PATH` in `InstallationPathConfig`;
`getPrivateKeyPath()` now resolves to `backup/keys` and new
`getBackupPath()` returns `backup/db`.
- Removed old `PRIVATE_KEY_PATH` and switched all usages to the new
locations.
  - Database service enhancements:
- `DatabaseService` now uses `InstallationPathConfig.getBackupPath()`
and includes a one-time migration to move existing backups from
`config/db/backup` to `config/backup/db` (**@Deprecated(since = "2.0.0",
forRemoval = true)**).
- Added `deleteAllBackups()` and `deleteLastBackup()` methods and
exposed them via a new Enterprise controller.
  - New Enterprise-only API:
    - Added `DatabaseControllerEnterprise` with:
      - `DELETE /api/v1/database/deleteAll` — delete all backup files.
- `DELETE /api/v1/database/deleteLast` — delete the most recent backup.
- Endpoints gated by `@EnterpriseEndpoint` and
`@Conditional(H2SQLCondition.class)`.
  - Key persistence adjustments:
- `KeyPersistenceService` now migrates keys from `config/db/keys` to
`config/backup/keys` on startup (**@Deprecated(since = "2.0.0",
forRemoval = true)**).
  - Miscellaneous refactors/fixes:
- Switched driver resolution in `DatabaseConfig` to a switch expression.
    - Corrected HTTP status usage to `HttpStatus.SEE_OTHER`.
- Removed constructor `runningEE` flag from `AccountWebController` and
replaced EE checks with `@EnterpriseEndpoint`.
- Minor test and annotation improvements (e.g., `@Deprecated(since =
"0.45.0")`, method references, equals order).
  
- **Why the change was made**
- To standardize and future-proof storage locations for both backups and
keys under a clear `config/backup` hierarchy.
- To give Enterprise admins first-class, safe cleanup endpoints for
managing backup retention without manual file operations.
- To reduce conditional logic in controllers and rely on declarative EE
gating.
- To improve maintainability and correctness (status codes, switch
expression, null-safety patterns).

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-24 22:16:55 +01:00
LudyandCopilot 40cf337b23 feat(ssrf): enhance private IP detection and IPv6 handling (#4191)
# Description of Changes

- Refactored `isPrivateAddress` to improve detection of private and
local addresses for both IPv4 and IPv6.
- Added explicit handling for:
  - IPv4-mapped IPv6 addresses
  - IPv6 link-local, site-local, and unique local (fc00::/7) addresses
  - Additional IPv4 private ranges such as link-local (169.254.0.0/16)
- Introduced `normalizeIpv4MappedAddress` to standardize IP checks in
cloud metadata detection.
- Replaced `switch` statement with modern `switch` expression for
cleaner control flow.

These changes were made to strengthen SSRF protection by covering more
address edge cases, especially in mixed IPv4/IPv6 environments.
This also improves detection of cloud metadata endpoints when accessed
via IPv4-mapped IPv6 addresses.


---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-24 22:08:29 +01:00
Ludy f5f011f1e0 deps: Pin Python dev dependencies and lock hashes to remediate security alert 302 (#4173)
## Description of Changes

- **What was changed**
- Added `.github/scripts/requirements_dev.in` and an autogenerated,
hash-locked `.github/scripts/requirements_dev.txt` to control Python dev
dependencies via `pip-compile`.
- **Why the change was made**
- To remediate a GitHub code scanning alert by removing vulnerable
transitive ranges and ensuring reproducible installs with vetted
versions and hashes.
- **Any challenges encountered**
- Reconciling version constraints among image/PDF tooling (e.g., Pillow,
pdf2image, OpenCV, WeasyPrint) while keeping wheels available across CI
platforms.
- Ensuring the generated lockfile remains maintainable and can be
refreshed with `pip-compile` when needed.



Closes
#https://github.com/Stirling-Tools/Stirling-PDF/security/code-scanning/302

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-24 22:03:12 +01:00
Ludy 73df0ae1a8 fix(config): recreate settings.yml if missing or below minimal size threshold (#4166)
# Description of Changes

- Added logic to verify the `settings.yml` file’s existence **and**
ensure it has at least 31 lines (minimum valid config since `v0.13.0`).
- If the file exists but is too small, it is moved to a timestamped
`.bak` backup before creating a new one from the template.
- Added logging to show current line count and backup location for
better traceability.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-24 21:47:09 +01:00
Ludy f0cfd87a5a build(gradle): replace deprecated outputFile with destinationFile in writeVersion task (#4167)
# Description of Changes

- Replaced the deprecated `outputFile` property with `destinationFile`
in the `writeVersion` Gradle task.
- Updated the logging statement to use
`destinationFile.get().asFile.path` instead of the old
`outputFile.path`.
- This change ensures compatibility with newer Gradle versions and
removes deprecation warnings.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-24 21:45:26 +01:00
Ludy 97132c28a4 build(gradle): include all subprojects in license report generation (#4170)
# Description of Changes

- Updated `build.gradle` to ensure the `licenseReport` task processes
both the root project and all subprojects.
- Introduced `allProjects` variable that merges `subprojects` with the
current project into a single set.
- This change ensures license reporting covers the full multi-module
project rather than only the root module.


---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-24 21:44:50 +01:00
LudyandCopilot 930fcf01bf fix(downloader): reset progress bar after completion (#4192)
# Description of Changes

- Added a `setTimeout` to hide the `.progressBarContainer` 1 second
after reaching 100%.
- Reset progress bar width to `0%` and `aria-valuenow` to `0` to prepare
for future downloads.
- This change ensures the UI does not leave a full progress bar
displayed after a completed download.


---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-24 21:42:31 +01:00
Peter Dave Hello d9a1ed6df1 Update and improve the zh-TW Traditional Chinese translation (#4164)
# Description of Changes

Update and improve the zh-TW Traditional Chinese translation

Summary from GitHub Copilot:

> This pull request updates the Traditional Chinese localization file
`messages_zh_TW.properties` to improve translation accuracy and
consistency across the UI. The changes focus on refining update-related
strings, clarifying PDF tool descriptions, and localizing bookmark
editor actions.
> 
> **Update & Upgrade Experience:**
> * Improved wording and localization for update notifications, modal
dialogs, update priority levels, and migration guide references to
better match native language conventions.
> * Refined enterprise edition feature descriptions, specifically
clarifying SSO login language for professional features.
> * Updated SSO login string for the login screen to use more natural
phrasing.
> 
> **PDF Tool Descriptions:**
> * Enhanced descriptions for "Auto Split PDF" and "PDF to Single
Page/Image" tools, making instructions clearer and terminology more
consistent.
[[1]](diffhunk://#diff-b982180d8edd5c66aef4cfc826fe1cabeb4d22644359f2f749ce0bec4760b40aL809-R809)
[[2]](diffhunk://#diff-b982180d8edd5c66aef4cfc826fe1cabeb4d22644359f2f749ce0bec4760b40aL1111-R1118)
[[3]](diffhunk://#diff-b982180d8edd5c66aef4cfc826fe1cabeb4d22644359f2f749ce0bec4760b40aL1431-R1431)
> 
> **Bookmark Editor Localization:**
> * Fully localized import/export actions and descriptions in the
bookmark editor, replacing English terms with accurate Chinese
equivalents.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [x] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-24 21:41:09 +01:00
Ludy 4a28c64dee fix(i18n): standardize {filename} placeholder in addPageNumbers.customNumberDesc across all translations (#4204)
# Description of Changes

- Standardized the placeholder for filename in
`addPageNumbers.customNumberDesc` to `{filename}` across all affected
translation files.
- Fixed inconsistent or localized variations (e.g., `{filnavn}`, `{ime
datoteke}`, `{nume_fisier}`, `{nome do arquivo}`, `{nama berkas}`) and
ensured the placeholder is uniform.
- Corrected missing closing braces and quotes in several language files.
- Affected locales include: `ar_AR`, `az_AZ`, `bg_BG`, `da_DK`, `el_GR`,
`en_GB`, `en_US`, `es_ES`, `ga_IE`, `hr_HR`, `id_ID`, `it_IT`, `nl_NL`,
`no_NB`, `pl_PL`, `pt_BR`, `pt_PT`, `ro_RO`, `sk_SK`, `sl_SI`,
`sr_LATN_RS`, `sv_SE`, `tr_TR`, `vi_VN`.



# @Frooodle please merge after
https://github.com/Stirling-Tools/Stirling-PDF/pull/4202

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-24 21:38:07 +01:00
Ludy cec5d1e1b6 ci(workflow): simplify PR deployment by removing redundant repo/ref lookup (#4266)
# Description of Changes

- Removed the separate step that fetched PR repository and ref
(`get-pr-info`).
- Simplified checkout by directly using `refs/pull/${{
needs.check-comment.outputs.pr_number }}/merge`.
- This reduces workflow complexity and avoids unnecessary API calls
while still supporting forked PRs.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-24 21:32:35 +01:00
Eray Türkay 4cd1de4101 Update messages_tr_TR.properties (#4274)
Translated 100% specifically into Turkish. No machine translation or
artificial intelligence was used. All files have been correctly
translated into Turkish together with the file providers.

Best regards.

- Türkay Software https://www.turkaysoftware.com

# Description of Changes

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [x] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [x] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [x] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-24 21:31:40 +01:00
stirlingbot[bot] 5fb207492e Update 3rd Party Licenses (#4247)
Auto-generated by stirlingbot[bot]

Signed-off-by: stirlingbot[bot] <stirlingbot[bot]@users.noreply.github.com>
Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2025-08-24 21:26:01 +01:00
Ludy 9779c75df4 refactor(tests): move & expand TextFinder/RedactController tests; fix TextFinder empty search-term handling; update token filtering API (#4264)
# Description of Changes

- **What was changed**
  - Relocated and refactored unit tests:
- `TextFinderTest` and `RedactControllerTest` moved under
`app/core/src/test/...` to align with module structure.
- Expanded test coverage: whole-word vs. partial matches, complex
regexes (emails, SSNs, IPs, currency), international/accented
characters, multi-page documents, malformed PDFs, operator preservation,
color decoding, and performance assertions.
  - **API adjustments in redaction flow**:
- `createTokensWithoutTargetText(...)` now accepts the `PDDocument`
alongside `PDPage` to properly manage resources/streams.
- Introduced/used `createPlaceholderWithFont(...)` to maintain text
width with explicit font context.
  - **Bug fix in `TextFinder`**:
- Early-return when the (trimmed) search term is empty to prevent
unnecessary processing and avoid false positives/errors.
- Minor cleanup (removed redundant `super()` call) and improved guard
logic around regex/whole-word wrapping.

- **Why the change was made**
- Improve reliability and determinism of PDF redaction and text finding
by exercising real-world patterns and edge cases.
- Ensure structural PDF operators (graphics/positioning) are preserved
during token filtering.
- Prevent crashes or misleading matches when users provide
empty/whitespace-only search terms.
- Align tests with the current project layout and increase
maintainability.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-24 21:20:28 +01:00
dependabot[bot] 2baa258e11 build(deps): bump io.micrometer:micrometer-core from 1.15.2 to 1.15.3 (#4190)
[//]: # (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
[io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer)
from 1.15.2 to 1.15.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/micrometer-metrics/micrometer/releases">io.micrometer:micrometer-core's
releases</a>.</em></p>
<blockquote>
<h2>1.15.3</h2>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Catch IllegalArgumentException in VirtualThreadMetrics <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/6584">#6584</a></li>
<li>Handle ArrayIndexOutOfBoundsException from DoubleHistogram in
TimeWindowPercentileHistogram.accumulate() defensively <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/6563">#6563</a></li>
<li>Sync OutputCapture from Spring Boot <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/6608">#6608</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Bump jersey3 from 3.1.10 to 3.1.11 <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/6607">#6607</a></li>
<li>Bump com.netflix.spectator:spectator-reg-atlas from 1.8.16 to 1.8.17
<a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/6600">#6600</a></li>
<li>Bump io.netty:netty-bom from 4.1.122.Final to 4.1.123.Final <a
href="https://redirect.github.com/micrometer-metrics/micrometer/pull/6537">#6537</a></li>
</ul>
<h2>❤️ Contributors</h2>
<p>Thank you to all the contributors who worked on this release:</p>
<p><a href="https://github.com/genuss"><code>@​genuss</code></a> and <a
href="https://github.com/izeye"><code>@​izeye</code></a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/micrometer-metrics/micrometer/commit/5b196107904eb875c0519e60dbba286439c2a343"><code>5b19610</code></a>
Merge branch '1.14.x' into 1.15.x</li>
<li><a
href="https://github.com/micrometer-metrics/micrometer/commit/942ac71ed57b27635cf045c605a181f75b1d04cd"><code>942ac71</code></a>
Fix javadoc in StringEscapeUtils</li>
<li><a
href="https://github.com/micrometer-metrics/micrometer/commit/240cdd34d1638b5ef677f92b679f74bef982940f"><code>240cdd3</code></a>
Merge branch '1.14.x' into 1.15.x</li>
<li><a
href="https://github.com/micrometer-metrics/micrometer/commit/7ef45eab42e8e6651330e50bb1cc5032936c7039"><code>7ef45ea</code></a>
Resolve AlmostJavadoc from Error Prone (<a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/6611">#6611</a>)</li>
<li><a
href="https://github.com/micrometer-metrics/micrometer/commit/f08fd1c1c894ef518b28ee15fed5765ac8c8de30"><code>f08fd1c</code></a>
Sync OutputCapture from Spring Boot (<a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/6608">#6608</a>)</li>
<li><a
href="https://github.com/micrometer-metrics/micrometer/commit/8f9ec4ffb18801537d215f02b3c5930b4f46862b"><code>8f9ec4f</code></a>
Bump jersey3 from 2.45 to 3.1.11 (<a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/6607">#6607</a>)</li>
<li><a
href="https://github.com/micrometer-metrics/micrometer/commit/1c200619262652a1fd052148dd00cf1fd1fa9566"><code>1c20061</code></a>
Bump jersey3 from 2.45 to 3.1.11 (<a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/6603">#6603</a>)</li>
<li><a
href="https://github.com/micrometer-metrics/micrometer/commit/f88770cf1964fce12bebc2dc11815846bf78da1b"><code>f88770c</code></a>
Merge branch '1.14.x' into 1.15.x</li>
<li><a
href="https://github.com/micrometer-metrics/micrometer/commit/69251027097473444b969b16f13bdf16a41a01eb"><code>6925102</code></a>
Polish (<a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/6602">#6602</a>)</li>
<li><a
href="https://github.com/micrometer-metrics/micrometer/commit/8c5048973dabe8f734af067d48cc9998b887d9c2"><code>8c50489</code></a>
Bump com.netflix.spectator:spectator-reg-atlas from 1.8.16 to 1.8.17 (<a
href="https://redirect.github.com/micrometer-metrics/micrometer/issues/6601">#6601</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/micrometer-metrics/micrometer/compare/v1.15.2...v1.15.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=io.micrometer:micrometer-core&package-manager=gradle&previous-version=1.15.2&new-version=1.15.3)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-24 21:17:32 +01:00
dependabot[bot] 3f004dcad3 build(deps): bump io.swagger.core.v3:swagger-core-jakarta from 2.2.35 to 2.2.36 (#4226)
Bumps io.swagger.core.v3:swagger-core-jakarta from 2.2.35 to 2.2.36.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=io.swagger.core.v3:swagger-core-jakarta&package-manager=gradle&previous-version=2.2.35&new-version=2.2.36)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-24 21:17:10 +01:00
dependabot[bot] 73d419cb39 build(deps): bump springSecuritySamlVersion from 6.5.2 to 6.5.3 (#4227)
Bumps `springSecuritySamlVersion` from 6.5.2 to 6.5.3.
Updates `org.springframework.security:spring-security-core` from 6.5.2
to 6.5.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-security/releases">org.springframework.security:spring-security-core's
releases</a>.</em></p>
<blockquote>
<h2>6.5.3</h2>
<h2> New Features</h2>
<ul>
<li>Add META-INF/LICENSE.txt to published jars <a
href="https://redirect.github.com/spring-projects/spring-security/issues/17639">#17639</a></li>
<li>Update Angular documentation links in csrf.adoc <a
href="https://redirect.github.com/spring-projects/spring-security/issues/17653">#17653</a></li>
<li>Update Shibboleth Repository URL <a
href="https://redirect.github.com/spring-projects/spring-security/issues/17637">#17637</a></li>
<li>Use 2004-present Copyright <a
href="https://redirect.github.com/spring-projects/spring-security/issues/17634">#17634</a></li>
</ul>
<h2>🪲 Bug Fixes</h2>
<ul>
<li>Add Missing Navigation in Preparing for 7.0 Guide <a
href="https://redirect.github.com/spring-projects/spring-security/issues/17731">#17731</a></li>
<li>DPoP authentication throws JwtDecoderFactory ClassNotFoundException
<a
href="https://redirect.github.com/spring-projects/spring-security/issues/17249">#17249</a></li>
<li>OpenSamlAssertingPartyDetails Should Be Serializable <a
href="https://redirect.github.com/spring-projects/spring-security/issues/17727">#17727</a></li>
<li>Use final values in equals and hashCode <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17621">#17621</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Bump com.webauthn4j:webauthn4j-core from 0.29.4.RELEASE to
0.29.5.RELEASE <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17739">#17739</a></li>
<li>Bump com.webauthn4j:webauthn4j-core from 0.29.4.RELEASE to
0.29.5.RELEASE <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17690">#17690</a></li>
<li>Bump com.webauthn4j:webauthn4j-core from 0.29.4.RELEASE to
0.29.5.RELEASE <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17684">#17684</a></li>
<li>Bump com.webauthn4j:webauthn4j-core from 0.29.4.RELEASE to
0.29.5.RELEASE <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17661">#17661</a></li>
<li>Bump io.micrometer:micrometer-observation from 1.14.8 to 1.14.9 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17615">#17615</a></li>
<li>Bump io.micrometer:micrometer-observation from 1.14.8 to 1.14.9 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17599">#17599</a></li>
<li>Bump io.micrometer:micrometer-observation from 1.14.9 to 1.14.10 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17737">#17737</a></li>
<li>Bump io.micrometer:micrometer-observation from 1.14.9 to 1.14.10 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17701">#17701</a></li>
<li>Bump io.mockk:mockk from 1.14.4 to 1.14.5 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17614">#17614</a></li>
<li>Bump io.spring.develocity.conventions from 0.0.23 to 0.0.24 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17647">#17647</a></li>
<li>Bump io.spring.gradle:spring-security-release-plugin from 1.0.10 to
1.0.11 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17733">#17733</a></li>
<li>Bump io.spring.gradle:spring-security-release-plugin from 1.0.10 to
1.0.11 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17711">#17711</a></li>
<li>Bump io.spring.gradle:spring-security-release-plugin from 1.0.6 to
1.0.10 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17612">#17612</a></li>
<li>Bump io.spring.gradle:spring-security-release-plugin from 1.0.6 to
1.0.10 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17598">#17598</a></li>
<li>Bump org-eclipse-jetty from 11.0.25 to 11.0.26 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17742">#17742</a></li>
<li>Bump org.apache.maven:maven-resolver-provider from 3.9.10 to 3.9.11
<a
href="https://redirect.github.com/spring-projects/spring-security/pull/17613">#17613</a></li>
<li>Bump org.apache.maven:maven-resolver-provider from 3.9.10 to 3.9.11
<a
href="https://redirect.github.com/spring-projects/spring-security/pull/17595">#17595</a></li>
<li>Bump org.assertj:assertj-core from 3.27.3 to 3.27.4 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17760">#17760</a></li>
<li>Bump org.assertj:assertj-core from 3.27.3 to 3.27.4 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17692">#17692</a></li>
<li>Bump org.assertj:assertj-core from 3.27.3 to 3.27.4 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17683">#17683</a></li>
<li>Bump org.assertj:assertj-core from 3.27.3 to 3.27.4 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17671">#17671</a></li>
<li>Bump org.gretty:gretty from 4.1.6 to 4.1.7 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17616">#17616</a></li>
<li>Bump org.gretty:gretty from 4.1.6 to 4.1.7 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17597">#17597</a></li>
<li>Bump org.hibernate.orm:hibernate-core from 6.6.20.Final to
6.6.23.Final <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17646">#17646</a></li>
<li>Bump org.hibernate.orm:hibernate-core from 6.6.23.Final to
6.6.24.Final <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17660">#17660</a></li>
<li>Bump org.hibernate.orm:hibernate-core from 6.6.23.Final to
6.6.25.Final <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17694">#17694</a></li>
<li>Bump org.hibernate.orm:hibernate-core from 6.6.23.Final to
6.6.25.Final <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17685">#17685</a></li>
<li>Bump org.jfrog.buildinfo:build-info-extractor-gradle from 4.34.1 to
4.34.2 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17650">#17650</a></li>
<li>Bump org.springframework.data:spring-data-bom from 2024.1.7 to
2024.1.8 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17645">#17645</a></li>
<li>Bump org.springframework.ldap:spring-ldap-core from 3.2.13 to 3.2.14
<a
href="https://redirect.github.com/spring-projects/spring-security/pull/17757">#17757</a></li>
<li>Bump org.springframework:spring-framework-bom from 6.2.8 to 6.2.9 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17651">#17651</a></li>
<li>Bump org.springframework:spring-framework-bom from 6.2.8 to 6.2.9 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17596">#17596</a></li>
<li>Bump org.springframework:spring-framework-bom from 6.2.9 to 6.2.10
<a
href="https://redirect.github.com/spring-projects/spring-security/pull/17735">#17735</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/spring-projects/spring-security/commit/44037c0ea4103dc599a84c0772f65c3aa4b6225f"><code>44037c0</code></a>
Release 6.5.3</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/9909dc615a59baead33ff050ff2825a73426268f"><code>9909dc6</code></a>
Merge branch '6.4.x' into 6.5.x</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/525601ea6782a49ae3fa66b4af98a3006dfce519"><code>525601e</code></a>
Fix version 6.4.9-SNAPSHOT</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/15a4d0d6279496c4f7f977cf1b1e616a1d6b31e2"><code>15a4d0d</code></a>
Fix version=6.5.3-SNAPSHOT</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/80b1a308abb4e32213c3e8671d50cbfa153a0d0a"><code>80b1a30</code></a>
Merge branch '6.4.x' into 6.5.x</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/644f7802d8bf21043286088a1c8cb28738fa3ebb"><code>644f780</code></a>
Bump org.springframework.ldap:spring-ldap-core from 3.2.13 to
3.2.14</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/a26d6fccb049576a2c438485aed535d60dcdcc0b"><code>a26d6fc</code></a>
Bump org.springframework.data:spring-data-bom from 2024.1.8 to
2024.1.9</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/74735a1a80efb9b6e907e7fe4780d58ae72ee911"><code>74735a1</code></a>
Bump org.hibernate.orm:hibernate-core from 6.6.23.Final to
6.6.26.Final</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/82a16d791776e7a8bb8e0efaaa3c5677aa6645c1"><code>82a16d7</code></a>
Bump org.assertj:assertj-core from 3.27.3 to 3.27.4</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/c1869c1db9105b8feb82f2128077376a606ead01"><code>c1869c1</code></a>
Bump org.hibernate.orm:hibernate-core from 6.6.23.Final to
6.6.26.Final</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-security/compare/6.5.2...6.5.3">compare
view</a></li>
</ul>
</details>
<br />

Updates
`org.springframework.security:spring-security-saml2-service-provider`
from 6.5.2 to 6.5.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-security/releases">org.springframework.security:spring-security-saml2-service-provider's
releases</a>.</em></p>
<blockquote>
<h2>6.5.3</h2>
<h2> New Features</h2>
<ul>
<li>Add META-INF/LICENSE.txt to published jars <a
href="https://redirect.github.com/spring-projects/spring-security/issues/17639">#17639</a></li>
<li>Update Angular documentation links in csrf.adoc <a
href="https://redirect.github.com/spring-projects/spring-security/issues/17653">#17653</a></li>
<li>Update Shibboleth Repository URL <a
href="https://redirect.github.com/spring-projects/spring-security/issues/17637">#17637</a></li>
<li>Use 2004-present Copyright <a
href="https://redirect.github.com/spring-projects/spring-security/issues/17634">#17634</a></li>
</ul>
<h2>🪲 Bug Fixes</h2>
<ul>
<li>Add Missing Navigation in Preparing for 7.0 Guide <a
href="https://redirect.github.com/spring-projects/spring-security/issues/17731">#17731</a></li>
<li>DPoP authentication throws JwtDecoderFactory ClassNotFoundException
<a
href="https://redirect.github.com/spring-projects/spring-security/issues/17249">#17249</a></li>
<li>OpenSamlAssertingPartyDetails Should Be Serializable <a
href="https://redirect.github.com/spring-projects/spring-security/issues/17727">#17727</a></li>
<li>Use final values in equals and hashCode <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17621">#17621</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Bump com.webauthn4j:webauthn4j-core from 0.29.4.RELEASE to
0.29.5.RELEASE <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17739">#17739</a></li>
<li>Bump com.webauthn4j:webauthn4j-core from 0.29.4.RELEASE to
0.29.5.RELEASE <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17690">#17690</a></li>
<li>Bump com.webauthn4j:webauthn4j-core from 0.29.4.RELEASE to
0.29.5.RELEASE <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17684">#17684</a></li>
<li>Bump com.webauthn4j:webauthn4j-core from 0.29.4.RELEASE to
0.29.5.RELEASE <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17661">#17661</a></li>
<li>Bump io.micrometer:micrometer-observation from 1.14.8 to 1.14.9 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17615">#17615</a></li>
<li>Bump io.micrometer:micrometer-observation from 1.14.8 to 1.14.9 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17599">#17599</a></li>
<li>Bump io.micrometer:micrometer-observation from 1.14.9 to 1.14.10 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17737">#17737</a></li>
<li>Bump io.micrometer:micrometer-observation from 1.14.9 to 1.14.10 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17701">#17701</a></li>
<li>Bump io.mockk:mockk from 1.14.4 to 1.14.5 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17614">#17614</a></li>
<li>Bump io.spring.develocity.conventions from 0.0.23 to 0.0.24 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17647">#17647</a></li>
<li>Bump io.spring.gradle:spring-security-release-plugin from 1.0.10 to
1.0.11 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17733">#17733</a></li>
<li>Bump io.spring.gradle:spring-security-release-plugin from 1.0.10 to
1.0.11 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17711">#17711</a></li>
<li>Bump io.spring.gradle:spring-security-release-plugin from 1.0.6 to
1.0.10 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17612">#17612</a></li>
<li>Bump io.spring.gradle:spring-security-release-plugin from 1.0.6 to
1.0.10 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17598">#17598</a></li>
<li>Bump org-eclipse-jetty from 11.0.25 to 11.0.26 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17742">#17742</a></li>
<li>Bump org.apache.maven:maven-resolver-provider from 3.9.10 to 3.9.11
<a
href="https://redirect.github.com/spring-projects/spring-security/pull/17613">#17613</a></li>
<li>Bump org.apache.maven:maven-resolver-provider from 3.9.10 to 3.9.11
<a
href="https://redirect.github.com/spring-projects/spring-security/pull/17595">#17595</a></li>
<li>Bump org.assertj:assertj-core from 3.27.3 to 3.27.4 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17760">#17760</a></li>
<li>Bump org.assertj:assertj-core from 3.27.3 to 3.27.4 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17692">#17692</a></li>
<li>Bump org.assertj:assertj-core from 3.27.3 to 3.27.4 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17683">#17683</a></li>
<li>Bump org.assertj:assertj-core from 3.27.3 to 3.27.4 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17671">#17671</a></li>
<li>Bump org.gretty:gretty from 4.1.6 to 4.1.7 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17616">#17616</a></li>
<li>Bump org.gretty:gretty from 4.1.6 to 4.1.7 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17597">#17597</a></li>
<li>Bump org.hibernate.orm:hibernate-core from 6.6.20.Final to
6.6.23.Final <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17646">#17646</a></li>
<li>Bump org.hibernate.orm:hibernate-core from 6.6.23.Final to
6.6.24.Final <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17660">#17660</a></li>
<li>Bump org.hibernate.orm:hibernate-core from 6.6.23.Final to
6.6.25.Final <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17694">#17694</a></li>
<li>Bump org.hibernate.orm:hibernate-core from 6.6.23.Final to
6.6.25.Final <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17685">#17685</a></li>
<li>Bump org.jfrog.buildinfo:build-info-extractor-gradle from 4.34.1 to
4.34.2 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17650">#17650</a></li>
<li>Bump org.springframework.data:spring-data-bom from 2024.1.7 to
2024.1.8 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17645">#17645</a></li>
<li>Bump org.springframework.ldap:spring-ldap-core from 3.2.13 to 3.2.14
<a
href="https://redirect.github.com/spring-projects/spring-security/pull/17757">#17757</a></li>
<li>Bump org.springframework:spring-framework-bom from 6.2.8 to 6.2.9 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17651">#17651</a></li>
<li>Bump org.springframework:spring-framework-bom from 6.2.8 to 6.2.9 <a
href="https://redirect.github.com/spring-projects/spring-security/pull/17596">#17596</a></li>
<li>Bump org.springframework:spring-framework-bom from 6.2.9 to 6.2.10
<a
href="https://redirect.github.com/spring-projects/spring-security/pull/17735">#17735</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/spring-projects/spring-security/commit/44037c0ea4103dc599a84c0772f65c3aa4b6225f"><code>44037c0</code></a>
Release 6.5.3</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/9909dc615a59baead33ff050ff2825a73426268f"><code>9909dc6</code></a>
Merge branch '6.4.x' into 6.5.x</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/525601ea6782a49ae3fa66b4af98a3006dfce519"><code>525601e</code></a>
Fix version 6.4.9-SNAPSHOT</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/15a4d0d6279496c4f7f977cf1b1e616a1d6b31e2"><code>15a4d0d</code></a>
Fix version=6.5.3-SNAPSHOT</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/80b1a308abb4e32213c3e8671d50cbfa153a0d0a"><code>80b1a30</code></a>
Merge branch '6.4.x' into 6.5.x</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/644f7802d8bf21043286088a1c8cb28738fa3ebb"><code>644f780</code></a>
Bump org.springframework.ldap:spring-ldap-core from 3.2.13 to
3.2.14</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/a26d6fccb049576a2c438485aed535d60dcdcc0b"><code>a26d6fc</code></a>
Bump org.springframework.data:spring-data-bom from 2024.1.8 to
2024.1.9</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/74735a1a80efb9b6e907e7fe4780d58ae72ee911"><code>74735a1</code></a>
Bump org.hibernate.orm:hibernate-core from 6.6.23.Final to
6.6.26.Final</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/82a16d791776e7a8bb8e0efaaa3c5677aa6645c1"><code>82a16d7</code></a>
Bump org.assertj:assertj-core from 3.27.3 to 3.27.4</li>
<li><a
href="https://github.com/spring-projects/spring-security/commit/c1869c1db9105b8feb82f2128077376a606ead01"><code>c1869c1</code></a>
Bump org.hibernate.orm:hibernate-core from 6.6.23.Final to
6.6.26.Final</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-security/compare/6.5.2...6.5.3">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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-24 21:16:57 +01:00
dependabot[bot] 44dbeebd40 build(deps): bump org.springframework.boot:spring-boot-dependencies from 3.5.4 to 3.5.5 (#4268)
Bumps
[org.springframework.boot:spring-boot-dependencies](https://github.com/spring-projects/spring-boot)
from 3.5.4 to 3.5.5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-boot/releases">org.springframework.boot:spring-boot-dependencies's
releases</a>.</em></p>
<blockquote>
<h2>v3.5.5</h2>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Hazelcast health indicator reports the wrong status when Hazelcast
has shut down due to an out-of-memory error <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46909">#46909</a></li>
<li>Performance critical tracing code has high overhead due to the use
of the Stream API <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46844">#46844</a></li>
<li>SpringLiquibaseCustomizer is exposed outside its defined visibility
scope <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46758">#46758</a></li>
<li>Race condition in OutputCapture can result in stale data <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46721">#46721</a></li>
<li>Auto-configured WebClient no longer uses context's
ReactorResourceFactory <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/46673">#46673</a></li>
<li>Default value not detected for a field annoted with
<code>@Name</code> <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46666">#46666</a></li>
<li>Missing metadata when using <code>@Name</code> with a
constructor-bound property <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46663">#46663</a></li>
<li>Missing property for Spring Authorization Server's PAR endpoint <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/46641">#46641</a></li>
<li>Property name is incorrect when reporting a mis-configured OAuth 2
Resource Server JWT public key location <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46636">#46636</a></li>
<li>Memory not freed on context restart in JpaMetamodel#CACHE with
spring.main.lazy-initialization=true <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46634">#46634</a></li>
<li>Auto-configured MockMvc ignores <code>@FilterRegistration</code>
annotation <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/46605">#46605</a></li>
<li>Failure to discover default value for a primitive should not lead to
document its default value <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46561">#46561</a></li>
</ul>
<h2>📔 Documentation</h2>
<ul>
<li>Kotlin samples for configuration metadata are in the wrong package
<a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46857">#46857</a></li>
<li>Observability examples in the reference guide are missing the Kotlin
version <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46798">#46798</a></li>
<li>Align method descriptions for SslOptions getCiphers and
getEnabledProtocols with <code>@returns</code> <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46769">#46769</a></li>
<li>Tracing samples in the reference guide are missing the Kotlin
version <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46767">#46767</a></li>
<li>Improve Virtual Threads section to mention the changes in Java 24 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46610">#46610</a></li>
<li>spring.test.webtestclient.timeout is not documented <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46588">#46588</a></li>
<li>spring-boot-test-autoconfigure should use the configuration
properties annotation processor like other modules <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46585">#46585</a></li>
<li>Adapt deprecation level for management.health.influxdb.enabled <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46580">#46580</a></li>
<li>spring.test.mockmvc properties are not documented <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46578">#46578</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Upgrade to Angus Mail 2.0.4 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46725">#46725</a></li>
<li>Upgrade to AssertJ 3.27.4 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46726">#46726</a></li>
<li>Upgrade to Byte Buddy 1.17.7 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46883">#46883</a></li>
<li>Upgrade to Couchbase Client 3.8.3 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46794">#46794</a></li>
<li>Upgrade to Elasticsearch Client 8.18.5 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46830">#46830</a></li>
<li>Upgrade to Hibernate 6.6.26.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46884">#46884</a></li>
<li>Upgrade to Hibernate Validator 8.0.3.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46728">#46728</a></li>
<li>Upgrade to HikariCP 6.3.2 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46729">#46729</a></li>
<li>Upgrade to Jersey 3.1.11 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46730">#46730</a></li>
<li>Upgrade to Jetty 12.0.25 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46831">#46831</a></li>
<li>Upgrade to Jetty Reactive HTTPClient 4.0.11 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46885">#46885</a></li>
<li>Upgrade to jOOQ 3.19.25 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46808">#46808</a></li>
<li>Upgrade to MariaDB 3.5.5 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46779">#46779</a></li>
<li>Upgrade to Maven Javadoc Plugin 3.11.3 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46886">#46886</a></li>
<li>Upgrade to Micrometer 1.15.3 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46701">#46701</a></li>
<li>Upgrade to Micrometer Tracing 1.5.3 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46702">#46702</a></li>
<li>Upgrade to MySQL 9.4.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46732">#46732</a></li>
<li>Upgrade to Netty 4.1.124.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46832">#46832</a></li>
<li>Upgrade to Pulsar 4.0.6 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46733">#46733</a></li>
<li>Upgrade to Reactor Bom 2024.0.9 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46703">#46703</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/3537d255b579018851951da08262cd0178e40c66"><code>3537d25</code></a>
Release v3.5.5</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/a22e28e9e00eca994b8e412a420110da5b58b64a"><code>a22e28e</code></a>
Merge branch '3.4.x' into 3.5.x</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/4cb8c8a1b9670497046655393ab2a0f535e8442d"><code>4cb8c8a</code></a>
Next development version (v3.4.10-SNAPSHOT)</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/9d205e21c4c007b317cc3c65bf8dcad543e61c81"><code>9d205e2</code></a>
Merge branch '3.4.x' into 3.5.x</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/47b06322d3df72d886d838a090f506a6ba281892"><code>47b0632</code></a>
Merge pull request <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46927">#46927</a>
from izeye</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/8b7145802503dc00720e24db67144e568648c96f"><code>8b71458</code></a>
Adapt checkstyle rules for 3.4.x</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/fb99badf16072b3e49aca422abe8e5be184b1af8"><code>fb99bad</code></a>
Remove redundant suppressions from Checkstyle configuration</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/8af836a428e65b8032483d5d8159099684054cd0"><code>8af836a</code></a>
Upgrade to Spring RESTDocs 3.0.5</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/ae6c6a5ed4652134c8f35fb8ca9a3d0149a207c2"><code>ae6c6a5</code></a>
Merge branch '3.4.x' into 3.5.x</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/b6bae9f59b38a2dc8234d2766b062a5986410a37"><code>b6bae9f</code></a>
Upgrade to Spring RESTDocs 3.0.5</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-boot/compare/v3.5.4...v3.5.5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.springframework.boot:spring-boot-dependencies&package-manager=gradle&previous-version=3.5.4&new-version=3.5.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-24 21:05:37 +01:00
dependabot[bot] 0d63bc4a41 build(deps): bump github/codeql-action from 3.29.10 to 3.29.11 (#4271)
Bumps [github/codeql-action](https://github.com/github/codeql-action)
from 3.29.10 to 3.29.11.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action's
releases</a>.</em></p>
<blockquote>
<h2>v3.29.11</h2>
<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>3.29.11 - 21 Aug 2025</h2>
<ul>
<li>Update default CodeQL bundle version to 2.22.4. <a
href="https://redirect.github.com/github/codeql-action/pull/3044">#3044</a></li>
</ul>
<p>See the full <a
href="https://github.com/github/codeql-action/blob/v3.29.11/CHANGELOG.md">CHANGELOG.md</a>
for more information.</p>
</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'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>3.29.11 - 21 Aug 2025</h2>
<ul>
<li>Update default CodeQL bundle version to 2.22.4. <a
href="https://redirect.github.com/github/codeql-action/pull/3044">#3044</a></li>
</ul>
<h2>3.29.10 - 18 Aug 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.9 - 12 Aug 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.8 - 08 Aug 2025</h2>
<ul>
<li>Fix an issue where the Action would autodetect unsupported languages
such as HTML. <a
href="https://redirect.github.com/github/codeql-action/pull/3015">#3015</a></li>
</ul>
<h2>3.29.7 - 07 Aug 2025</h2>
<p>This release rolls back 3.29.6 to address issues with language
autodetection. It is identical to 3.29.5.</p>
<h2>3.29.6 - 07 Aug 2025</h2>
<ul>
<li>The <code>cleanup-level</code> input to the <code>analyze</code>
Action is now deprecated. The CodeQL Action has written a limited amount
of intermediate results to the database since version 2.2.5, and now
automatically manages cleanup. <a
href="https://redirect.github.com/github/codeql-action/pull/2999">#2999</a></li>
<li>Update default CodeQL bundle version to 2.22.3. <a
href="https://redirect.github.com/github/codeql-action/pull/3000">#3000</a></li>
</ul>
<h2>3.29.5 - 29 Jul 2025</h2>
<ul>
<li>Update default CodeQL bundle version to 2.22.2. <a
href="https://redirect.github.com/github/codeql-action/pull/2986">#2986</a></li>
</ul>
<h2>3.29.4 - 23 Jul 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.3 - 21 Jul 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.2 - 30 Jun 2025</h2>
<ul>
<li>Experimental: When the <code>quality-queries</code> input for the
<code>init</code> action is provided with an argument, separate
<code>.quality.sarif</code> files are produced and uploaded for each
language with the results of the specified queries. Do not use this in
production as it is part of an internal experiment and subject to change
at any time. <a
href="https://redirect.github.com/github/codeql-action/pull/2935">#2935</a></li>
</ul>
<h2>3.29.1 - 27 Jun 2025</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/3c3833e0f8c1c83d449a7478aa59c036a9165498"><code>3c3833e</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3052">#3052</a>
from github/update-v3.29.11-14148a433</li>
<li><a
href="https://github.com/github/codeql-action/commit/8c4bfbd99ba6ef652eca12461ad7618142e00679"><code>8c4bfbd</code></a>
Update changelog for v3.29.11</li>
<li><a
href="https://github.com/github/codeql-action/commit/14148a433d789d9b6c7dadb56d8e3f8ad1e59605"><code>14148a4</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3044">#3044</a>
from github/update-bundle/codeql-bundle-v2.22.4</li>
<li><a
href="https://github.com/github/codeql-action/commit/71b2cb38a1e682cb9b2453a5f1400eef870a37df"><code>71b2cb3</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/2bf78254cceec27aab20b1623ba68c63c6eb85c6"><code>2bf7825</code></a>
Update default bundle to codeql-bundle-v2.22.4</li>
<li><a
href="https://github.com/github/codeql-action/commit/db69a5182d331d562e511302ae3c9aafd5fada6c"><code>db69a51</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3049">#3049</a>
from github/update-supported-enterprise-server-versions</li>
<li><a
href="https://github.com/github/codeql-action/commit/a68d47bfa574c69f3de7d6484cf28a9c55ff7287"><code>a68d47b</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3050">#3050</a>
from github/henrymercer/init-not-called-config-error</li>
<li><a
href="https://github.com/github/codeql-action/commit/e496ff959372e828f30b1518fd22cb76170cf5db"><code>e496ff9</code></a>
Make &quot;init not called&quot; a configuration error</li>
<li><a
href="https://github.com/github/codeql-action/commit/fd2ea72d34cdf8157d85d93decf87671705166a3"><code>fd2ea72</code></a>
Update supported GitHub Enterprise Server versions</li>
<li><a
href="https://github.com/github/codeql-action/commit/6dee5bc9c165ca206a70f4e3d18271971cf6ff26"><code>6dee5bc</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3045">#3045</a>
from github/dependabot/npm_and_yarn/npm-5b4171dd16</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/96f518a34f7a870018057716cc4d7a5c014bd61c...3c3833e0f8c1c83d449a7478aa59c036a9165498">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=3.29.10&new-version=3.29.11)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-24 21:04:24 +01:00
dependabot[bot] ae53492751 build(deps): bump org.springframework.boot from 3.5.4 to 3.5.5 (#4272)
Bumps
[org.springframework.boot](https://github.com/spring-projects/spring-boot)
from 3.5.4 to 3.5.5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-boot/releases">org.springframework.boot's
releases</a>.</em></p>
<blockquote>
<h2>v3.5.5</h2>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Hazelcast health indicator reports the wrong status when Hazelcast
has shut down due to an out-of-memory error <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46909">#46909</a></li>
<li>Performance critical tracing code has high overhead due to the use
of the Stream API <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46844">#46844</a></li>
<li>SpringLiquibaseCustomizer is exposed outside its defined visibility
scope <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46758">#46758</a></li>
<li>Race condition in OutputCapture can result in stale data <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46721">#46721</a></li>
<li>Auto-configured WebClient no longer uses context's
ReactorResourceFactory <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/46673">#46673</a></li>
<li>Default value not detected for a field annoted with
<code>@Name</code> <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46666">#46666</a></li>
<li>Missing metadata when using <code>@Name</code> with a
constructor-bound property <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46663">#46663</a></li>
<li>Missing property for Spring Authorization Server's PAR endpoint <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/46641">#46641</a></li>
<li>Property name is incorrect when reporting a mis-configured OAuth 2
Resource Server JWT public key location <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46636">#46636</a></li>
<li>Memory not freed on context restart in JpaMetamodel#CACHE with
spring.main.lazy-initialization=true <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46634">#46634</a></li>
<li>Auto-configured MockMvc ignores <code>@FilterRegistration</code>
annotation <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/46605">#46605</a></li>
<li>Failure to discover default value for a primitive should not lead to
document its default value <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46561">#46561</a></li>
</ul>
<h2>📔 Documentation</h2>
<ul>
<li>Kotlin samples for configuration metadata are in the wrong package
<a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46857">#46857</a></li>
<li>Observability examples in the reference guide are missing the Kotlin
version <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46798">#46798</a></li>
<li>Align method descriptions for SslOptions getCiphers and
getEnabledProtocols with <code>@returns</code> <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46769">#46769</a></li>
<li>Tracing samples in the reference guide are missing the Kotlin
version <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46767">#46767</a></li>
<li>Improve Virtual Threads section to mention the changes in Java 24 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46610">#46610</a></li>
<li>spring.test.webtestclient.timeout is not documented <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46588">#46588</a></li>
<li>spring-boot-test-autoconfigure should use the configuration
properties annotation processor like other modules <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46585">#46585</a></li>
<li>Adapt deprecation level for management.health.influxdb.enabled <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46580">#46580</a></li>
<li>spring.test.mockmvc properties are not documented <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46578">#46578</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Upgrade to Angus Mail 2.0.4 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46725">#46725</a></li>
<li>Upgrade to AssertJ 3.27.4 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46726">#46726</a></li>
<li>Upgrade to Byte Buddy 1.17.7 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46883">#46883</a></li>
<li>Upgrade to Couchbase Client 3.8.3 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46794">#46794</a></li>
<li>Upgrade to Elasticsearch Client 8.18.5 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46830">#46830</a></li>
<li>Upgrade to Hibernate 6.6.26.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46884">#46884</a></li>
<li>Upgrade to Hibernate Validator 8.0.3.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46728">#46728</a></li>
<li>Upgrade to HikariCP 6.3.2 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46729">#46729</a></li>
<li>Upgrade to Jersey 3.1.11 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46730">#46730</a></li>
<li>Upgrade to Jetty 12.0.25 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46831">#46831</a></li>
<li>Upgrade to Jetty Reactive HTTPClient 4.0.11 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46885">#46885</a></li>
<li>Upgrade to jOOQ 3.19.25 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46808">#46808</a></li>
<li>Upgrade to MariaDB 3.5.5 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46779">#46779</a></li>
<li>Upgrade to Maven Javadoc Plugin 3.11.3 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46886">#46886</a></li>
<li>Upgrade to Micrometer 1.15.3 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46701">#46701</a></li>
<li>Upgrade to Micrometer Tracing 1.5.3 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46702">#46702</a></li>
<li>Upgrade to MySQL 9.4.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46732">#46732</a></li>
<li>Upgrade to Netty 4.1.124.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46832">#46832</a></li>
<li>Upgrade to Pulsar 4.0.6 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46733">#46733</a></li>
<li>Upgrade to Reactor Bom 2024.0.9 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46703">#46703</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/3537d255b579018851951da08262cd0178e40c66"><code>3537d25</code></a>
Release v3.5.5</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/a22e28e9e00eca994b8e412a420110da5b58b64a"><code>a22e28e</code></a>
Merge branch '3.4.x' into 3.5.x</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/4cb8c8a1b9670497046655393ab2a0f535e8442d"><code>4cb8c8a</code></a>
Next development version (v3.4.10-SNAPSHOT)</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/9d205e21c4c007b317cc3c65bf8dcad543e61c81"><code>9d205e2</code></a>
Merge branch '3.4.x' into 3.5.x</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/47b06322d3df72d886d838a090f506a6ba281892"><code>47b0632</code></a>
Merge pull request <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/46927">#46927</a>
from izeye</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/8b7145802503dc00720e24db67144e568648c96f"><code>8b71458</code></a>
Adapt checkstyle rules for 3.4.x</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/fb99badf16072b3e49aca422abe8e5be184b1af8"><code>fb99bad</code></a>
Remove redundant suppressions from Checkstyle configuration</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/8af836a428e65b8032483d5d8159099684054cd0"><code>8af836a</code></a>
Upgrade to Spring RESTDocs 3.0.5</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/ae6c6a5ed4652134c8f35fb8ca9a3d0149a207c2"><code>ae6c6a5</code></a>
Merge branch '3.4.x' into 3.5.x</li>
<li><a
href="https://github.com/spring-projects/spring-boot/commit/b6bae9f59b38a2dc8234d2766b062a5986410a37"><code>b6bae9f</code></a>
Upgrade to Spring RESTDocs 3.0.5</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-boot/compare/v3.5.4...v3.5.5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.springframework.boot&package-manager=gradle&previous-version=3.5.4&new-version=3.5.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-24 21:03:53 +01:00
dependabot[bot] 1d89917e88 build(deps): bump org.springdoc:springdoc-openapi-starter-webmvc-ui from 2.8.9 to 2.8.11 (#4273)
Bumps
[org.springdoc:springdoc-openapi-starter-webmvc-ui](https://github.com/springdoc/springdoc-openapi)
from 2.8.9 to 2.8.11.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/springdoc/springdoc-openapi/releases">org.springdoc:springdoc-openapi-starter-webmvc-ui's
releases</a>.</em></p>
<blockquote>
<h2>springdoc-openapi v2.8.11 released!</h2>
<h3>Added</h3>
<ul>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3065">#3065</a>
- javadoc and overall performance optimization</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Upgrade spring-boot to v3.5.5</li>
</ul>
<h3>Fixed</h3>
<ul>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3064">#3064</a>
-ClassNotFoundException: kotlin.reflect.full.KClasses</li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/rayuuuu"><code>@​rayuuuu</code></a> made
their first contribution in <a
href="https://redirect.github.com/springdoc/springdoc-openapi/pull/3065">springdoc/springdoc-openapi#3065</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/springdoc/springdoc-openapi/compare/v2.8.10...v2.8.11">https://github.com/springdoc/springdoc-openapi/compare/v2.8.10...v2.8.11</a></p>
<h2>springdoc-openapi v2.8.10 released!</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix unexpected merging of media types by <a
href="https://github.com/Mattias-Sehlstedt"><code>@​Mattias-Sehlstedt</code></a>
in <a
href="https://redirect.github.com/springdoc/springdoc-openapi/pull/3026">springdoc/springdoc-openapi#3026</a></li>
<li>Fixed &quot;desciption&quot; typo by <a
href="https://github.com/lc-nyovchev"><code>@​lc-nyovchev</code></a> in
<a
href="https://redirect.github.com/springdoc/springdoc-openapi/pull/3036">springdoc/springdoc-openapi#3036</a></li>
<li>Fix: Property resolution for extensions within
<code>@OpenAPIDefinition</code> Info object by <a
href="https://github.com/limehee"><code>@​limehee</code></a> in <a
href="https://redirect.github.com/springdoc/springdoc-openapi/pull/3039">springdoc/springdoc-openapi#3039</a></li>
<li>Support externalDocs configure on SpecPropertiesCustomizer by <a
href="https://github.com/huisam"><code>@​huisam</code></a> in <a
href="https://redirect.github.com/springdoc/springdoc-openapi/pull/3042">springdoc/springdoc-openapi#3042</a></li>
<li>Use adaptFromForwardedHeaders instead of deprecated fromHttpRequest
by <a
href="https://github.com/thijsnissen"><code>@​thijsnissen</code></a> in
<a
href="https://redirect.github.com/springdoc/springdoc-openapi/pull/3060">springdoc/springdoc-openapi#3060</a></li>
<li>Fixes so that a RequestPart with a Map is added to the RequestBody
by <a
href="https://github.com/Mattias-Sehlstedt"><code>@​Mattias-Sehlstedt</code></a>
in <a
href="https://redirect.github.com/springdoc/springdoc-openapi/pull/3051">springdoc/springdoc-openapi#3051</a></li>
<li>Refactor webhook discovery and scanning mechanism by <a
href="https://github.com/zdary"><code>@​zdary</code></a> in <a
href="https://redirect.github.com/springdoc/springdoc-openapi/pull/3057">springdoc/springdoc-openapi#3057</a></li>
</ul>
<h3>Added</h3>
<ul>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3046">#3046</a>
- Feature Request: Support <a
href="https://github.com/jakarta"><code>@​jakarta</code></a>.annotation.Nonnull.</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3042">#3042</a>
- Support externalDocs configure on SpecPropertiesCustomizer</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3057">#3057</a>
- Refactor webhook discovery and scanning mechanism</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Upgrade spring-boot to v3.5.4</li>
<li>Upgrade swagger-ui to v5.27.1</li>
<li>Upgrade swagger-core to 2.2.36</li>
</ul>
<h3>Fixed</h3>
<ul>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3050">#3050</a>
- <a
href="https://github.com/RequestPart"><code>@​RequestPart</code></a>
JSON parameters missing Content-Type in generated curl commands, causing
415 errors.</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/2978">#2978</a>
- Parameter is no longer optional after upgrade to 2.8.8</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3022">#3022</a>
- NullPointerException thrown in SchemaUtils.</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3026">#3026</a>
- Fix unexpected merging of media types</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3036">#3036</a>
- Fixed &quot;desciption&quot;</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3039">#3039</a>
- Fix: Property resolution for extensions within <a
href="https://github.com/OpenAPIDefinition"><code>@​OpenAPIDefinition</code></a>
Info object</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3051">#3051</a>
- Fixes so that a RequestPart with a Map is added to the
RequestBody</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3060">#3060</a>
- Use adaptFromForwardedHeaders instead of deprecated
fromHttpRequest</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/springdoc/springdoc-openapi/blob/main/CHANGELOG.md">org.springdoc:springdoc-openapi-starter-webmvc-ui's
changelog</a>.</em></p>
<blockquote>
<h2>[2.8.11] - 2025-08-23</h2>
<h3>Added</h3>
<ul>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3065">#3065</a>
- javadoc and overall performance optimization</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Upgrade spring-boot to v3.5.5</li>
</ul>
<h3>Fixed</h3>
<ul>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3064">#3064</a>
-ClassNotFoundException: kotlin.reflect.full.KClasses</li>
</ul>
<h2>[2.8.10] - 2025-08-20</h2>
<h3>Added</h3>
<ul>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3046">#3046</a>
- Feature Request: Support <a
href="https://github.com/jakarta"><code>@​jakarta</code></a>.annotation.Nonnull.</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3042">#3042</a>
- Support externalDocs configure on SpecPropertiesCustomizer</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3057">#3057</a>
- Refactor webhook discovery and scanning mechanism</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Upgrade spring-boot to v3.5.4</li>
<li>Upgrade swagger-ui to v5.27.1</li>
<li>Upgrade swagger-core to 2.2.36</li>
</ul>
<h3>Fixed</h3>
<ul>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3050">#3050</a>
- <a
href="https://github.com/RequestPart"><code>@​RequestPart</code></a>
JSON parameters missing Content-Type in generated curl commands, causing
415 errors.</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/2978">#2978</a>
- Parameter is no longer optional after upgrade to 2.8.8</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3022">#3022</a>
- NullPointerException thrown in SchemaUtils.</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3026">#3026</a>
- Fix unexpected merging of media types</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3036">#3036</a>
- Fixed &quot;desciption&quot;</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3039">#3039</a>
- Fix: Property resolution for extensions within <a
href="https://github.com/OpenAPIDefinition"><code>@​OpenAPIDefinition</code></a>
Info object</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3051">#3051</a>
- Fixes so that a RequestPart with a Map is added to the
RequestBody</li>
<li><a
href="https://redirect.github.com/springdoc/springdoc-openapi/issues/3060">#3060</a>
- Use adaptFromForwardedHeaders instead of deprecated
fromHttpRequest</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/1cf8e58c4dd635520e377bea82be8821df8013ac"><code>1cf8e58</code></a>
[maven-release-plugin] prepare release v2.8.11</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/9d811218ebce2c772a1964634485c579ab9f3622"><code>9d81121</code></a>
CHANGELOG.md update</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/00d8525df43e5ecddcc81214aa013b42c62b8480"><code>00d8525</code></a>
performance tunning</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/fba01145d3fdb6d0a9d5105d3bdaf743fdea146d"><code>fba0114</code></a>
upgrade to spring-boot 3.5.5</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/957b4a91644f4148ed17a276780b3f5d3376d287"><code>957b4a9</code></a>
Merge branch 'rayuuuu-main'</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/5823621fe367c7531d565401b609a2202dd2aeb4"><code>5823621</code></a>
Merge branch 'main' of <a
href="https://github.com/rayuuuu/springdoc-openapi">https://github.com/rayuuuu/springdoc-openapi</a>
into rayu...</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/133b4c335849473135d43fa9c922a5439e6bcd36"><code>133b4c3</code></a>
java.lang.ClassNotFoundException: kotlin.reflect.full.KClasses when
upgrade f...</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/7be993e5b8c2f3c988c4cdec621ad7123f60aaf1"><code>7be993e</code></a>
feat: javadoc performance optimization</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/e1b9f7114a0660c7f9af6bd16bbe55efbe846194"><code>e1b9f71</code></a>
[maven-release-plugin] prepare for next development iteration</li>
<li><a
href="https://github.com/springdoc/springdoc-openapi/commit/2a59f95ff06b90023424e1021f6c8f09c87b21f5"><code>2a59f95</code></a>
[maven-release-plugin] prepare release v2.8.10</li>
<li>Additional commits viewable in <a
href="https://github.com/springdoc/springdoc-openapi/compare/v2.8.9...v2.8.11">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.springdoc:springdoc-openapi-starter-webmvc-ui&package-manager=gradle&previous-version=2.8.9&new-version=2.8.11)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-24 21:03:37 +01:00
Ludy 409cada93a chore(ci): include testing/** in file change detection for docker-compose-tests workflow (#4206)
# Description of Changes

- Added `testing/**` to `.github/config/.files.yaml` so that changes in
the `testing` directory will trigger the `docker-compose-tests` workflow
in `build.yml`.
- Updated Python dependencies in
`.github/scripts/requirements_pre_commit.txt` and
`testing/cucumber/requirements.txt` to newer versions, including
`behave`, `pypdf`, `reportlab`, and others.
- Introduced new dependencies like `colorama`, `cucumber-expressions`,
`cucumber-tag-expressions`, and `tomli` in the testing requirements to
support enhanced test execution.
- Ensured hash integrity for all dependency updates.

This change was made to ensure that modifications in the testing suite
automatically trigger relevant CI jobs and that testing dependencies
remain up-to-date for compatibility and stability.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-21 10:31:25 +01:00
Ludy c141a15215 refactor(build): centralize security disable condition in shared Gradle property (#4209)
# Description of Changes

- Introduced `ext.isSecurityDisabled` closure in root `build.gradle` to
consolidate logic for determining if security features should be
disabled.
- Removed duplicated conditional checks from `sourceSets` configurations
in both root and `app/core` `build.gradle` files.
- Updated dependency inclusion for `:proprietary` module to use the new
`isSecurityDisabled()` method for clarity and maintainability.
- Simplified build logic by reducing repeated environment and property
checks.

This change improves maintainability by ensuring that the security
disable condition is defined in one place, reducing the risk of
inconsistencies across modules.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-20 15:38:21 +01:00
Ludy ab7cef5a97 feat(common,core,proprietary): remove unused injections, enhance type safety, and improve test mocks (#4213)
# Description of Changes

This PR introduces several refactorings and minor enhancements across
the `common`, `core`, and `proprietary` modules:

- **Dependency Injection Cleanup**
- Removed unused constructor-injected dependencies (e.g.,
`FileOrUploadService`, `ApplicationProperties`, redundant `@Autowired`
annotations).
  - Simplified constructors to only require actively used dependencies.

- **Model Enhancements**
- Added `@NoArgsConstructor` to `FileInfo`, `PdfMetadata`, and
`SignatureFile` to improve serialization/deserialization support.

- **Service Improvements**
- Improved `JobExecutorService` content type retrieval by assigning
`MediaType` to a variable before conversion.
- Enhanced `KeyPersistenceService` with type-safe
`.filter(JwtVerificationKey.class::isInstance)`.
- Annotated `decodePublicKey` in `KeyPersistenceService` with
`@Override` for clarity.

- **Controller & API Changes**
- Updated `AdminSettingsController` to use
`TypeReference<Map<String,Object>>` for safer conversion.
- Improved long log and description strings with consistent formatting.

- **Testing Updates**
- Replaced `.lenient()` mock settings with
`.defaultAnswer(RETURNS_DEFAULTS)` for `FileToPdf` static mocks.
- Used `ArgumentMatchers.<TypeReference<List<BookmarkItem>>>any()` in
`EditTableOfContentsControllerTest` for type safety.
- Updated `UserServiceTest` default `AuthenticationType` from `SSO` to
`OAUTH2`.

- **Formatting**
  - Broke up long log/debug lines for better readability.
  - Removed redundant `@SuppressWarnings` where type safety was ensured.

These changes aim to make the codebase leaner, more type-safe, and
maintainable, while improving test reliability.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-20 15:36:39 +01:00
Ludy c10474fd30 fix(h2): refine SQL condition check for custom database flag (#4216)
# Description of Changes

- Refactored `H2SQLCondition.matches` to use `env.getProperty` with
proper default values and types.
- Adjusted logic to only return `false` when a custom database is
enabled and datasource type is not `h2`.
- Simplified environment variable handling for better readability and
robustness.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-20 15:35:24 +01:00
dependabot[bot] 246a59a794 build(deps): bump github/codeql-action from 3.29.8 to 3.29.10 (#4231)
Bumps [github/codeql-action](https://github.com/github/codeql-action)
from 3.29.8 to 3.29.10.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action's
releases</a>.</em></p>
<blockquote>
<h2>v3.29.10</h2>
<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>3.29.10 - 18 Aug 2025</h2>
<p>No user facing changes.</p>
<p>See the full <a
href="https://github.com/github/codeql-action/blob/v3.29.10/CHANGELOG.md">CHANGELOG.md</a>
for more information.</p>
<h2>v3.29.9</h2>
<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>3.29.9 - 12 Aug 2025</h2>
<p>No user facing changes.</p>
<p>See the full <a
href="https://github.com/github/codeql-action/blob/v3.29.9/CHANGELOG.md">CHANGELOG.md</a>
for more information.</p>
</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'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>3.29.10 - 18 Aug 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.9 - 12 Aug 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.8 - 08 Aug 2025</h2>
<ul>
<li>Fix an issue where the Action would autodetect unsupported languages
such as HTML. <a
href="https://redirect.github.com/github/codeql-action/pull/3015">#3015</a></li>
</ul>
<h2>3.29.7 - 07 Aug 2025</h2>
<p>This release rolls back 3.29.6 to address issues with language
autodetection. It is identical to 3.29.5.</p>
<h2>3.29.6 - 07 Aug 2025</h2>
<ul>
<li>The <code>cleanup-level</code> input to the <code>analyze</code>
Action is now deprecated. The CodeQL Action has written a limited amount
of intermediate results to the database since version 2.2.5, and now
automatically manages cleanup. <a
href="https://redirect.github.com/github/codeql-action/pull/2999">#2999</a></li>
<li>Update default CodeQL bundle version to 2.22.3. <a
href="https://redirect.github.com/github/codeql-action/pull/3000">#3000</a></li>
</ul>
<h2>3.29.5 - 29 Jul 2025</h2>
<ul>
<li>Update default CodeQL bundle version to 2.22.2. <a
href="https://redirect.github.com/github/codeql-action/pull/2986">#2986</a></li>
</ul>
<h2>3.29.4 - 23 Jul 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.3 - 21 Jul 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.2 - 30 Jun 2025</h2>
<ul>
<li>Experimental: When the <code>quality-queries</code> input for the
<code>init</code> action is provided with an argument, separate
<code>.quality.sarif</code> files are produced and uploaded for each
language with the results of the specified queries. Do not use this in
production as it is part of an internal experiment and subject to change
at any time. <a
href="https://redirect.github.com/github/codeql-action/pull/2935">#2935</a></li>
</ul>
<h2>3.29.1 - 27 Jun 2025</h2>
<ul>
<li>Fix bug in PR analysis where user-provided <code>include</code>
query filter fails to exclude non-included queries. <a
href="https://redirect.github.com/github/codeql-action/pull/2938">#2938</a></li>
<li>Update default CodeQL bundle version to 2.22.1. <a
href="https://redirect.github.com/github/codeql-action/pull/2950">#2950</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/96f518a34f7a870018057716cc4d7a5c014bd61c"><code>96f518a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3042">#3042</a>
from github/update-v3.29.10-6ec994ecb</li>
<li><a
href="https://github.com/github/codeql-action/commit/57a1c6b3e7be038f5eeeeb5323255e363f4b0100"><code>57a1c6b</code></a>
Update changelog for v3.29.10</li>
<li><a
href="https://github.com/github/codeql-action/commit/6ec994ecba29cf3cf0724e281b919d68714895ce"><code>6ec994e</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3039">#3039</a>
from github/mbg/remove-cpp-bmn-check</li>
<li><a
href="https://github.com/github/codeql-action/commit/3f00c7c1e1cf5d62a6dcd81509929718baa53e5f"><code>3f00c7c</code></a>
Remove unused C++ BMN FF</li>
<li><a
href="https://github.com/github/codeql-action/commit/141ee4abd8937999bf5108d222dd9f553490f3a8"><code>141ee4a</code></a>
Remove C++ BMN FF check that is no longer used</li>
<li><a
href="https://github.com/github/codeql-action/commit/233052189b8c862bfaf875fb02c115f54d2b9286"><code>2330521</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3037">#3037</a>
from github/henrymercer/failed-upload-logs</li>
<li><a
href="https://github.com/github/codeql-action/commit/3966569d06c954a63fdb79944f148b2f8b4ceed8"><code>3966569</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3035">#3035</a>
from github/henrymercer/fix-cleanup-info</li>
<li><a
href="https://github.com/github/codeql-action/commit/f7bd70c7faab9b863a52c058f145ec121b391925"><code>f7bd70c</code></a>
Merge branch 'main' into henrymercer/failed-upload-logs</li>
<li><a
href="https://github.com/github/codeql-action/commit/75151c27826716b79222a4d1ddac714dc37eff65"><code>75151c2</code></a>
Merge branch 'main' into henrymercer/fix-cleanup-info</li>
<li><a
href="https://github.com/github/codeql-action/commit/4ff91f10807d53419e564e2484e7045e207584b9"><code>4ff91f1</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3036">#3036</a>
from github/mbg/ci/gradle9</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/76621b61decf072c1cee8dd1ce2d2a82d33c17ed...96f518a34f7a870018057716cc4d7a5c014bd61c">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=3.29.8&new-version=3.29.10)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-20 15:34:26 +01:00
dependabot[bot] 12d4e26aa3 build(deps): bump jwtVersion from 0.12.6 to 0.12.7 (#4229)
Bumps `jwtVersion` from 0.12.6 to 0.12.7.
Updates `io.jsonwebtoken:jjwt-api` from 0.12.6 to 0.12.7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jwtk/jjwt/releases">io.jsonwebtoken:jjwt-api's
releases</a>.</em></p>
<blockquote>
<h2>0.12.7</h2>
<p>This patch release:</p>
<ul>
<li>
<p>Adds a new Maven BOM! This is useful for multi-module projects. See
<a href="https://redirect.github.com/jwtk/jjwt/issues/967">Issue
967</a>.</p>
</li>
<li>
<p>Allows the <code>JwtParserBuilder</code> to have empty nested
algorithm collections, effectively disabling the parser's associated
feature:</p>
<ul>
<li>Emptying the <code>zip()</code> nested collection disables JWT
decompression.</li>
<li>Emptying the <code>sig()</code> nested collection disables JWS
mac/signature verification (i.e. all JWSs will be
unsupported/rejected).</li>
<li>Emptying either the <code>enc()</code> or <code>key()</code> nested
collections disables JWE decryption (i.e. all JWEs will be
unsupported/rejected)</li>
</ul>
<p>See <a href="https://redirect.github.com/jwtk/jjwt/issues/996">Issue
996</a>.</p>
</li>
<li>
<p>Fixes <a href="https://redirect.github.com/jwtk/jjwt/issues/961">bug
961</a> where <code>JwtParserBuilder</code> nested collection builders
were not correctly replacing algorithms with the same id.</p>
</li>
<li>
<p>Ensures a <code>JwkSet</code>'s <code>keys</code> collection is no
longer entirely secret/redacted by default. This was an overzealous
default that was unnecessarily restrictive; the <code>keys</code>
collection itself should always be public, and each individual key
within should determine which fields should be redacted when printed.
See <a href="https://redirect.github.com/jwtk/jjwt/issues/976">Issue
976</a>.</p>
</li>
<li>
<p>Improves performance slightly by ensuring all <code>jjwt-api</code>
utility methods that create <code>*Builder</code> instances
(<code>Jwts.builder()</code>, <code>Jwts.parserBuilder()</code>,
<code>Jwks.builder()</code>, etc) no longer use reflection.</p>
<p>Instead,<code>static</code> factories are created via reflection only
once during initial <code>jjwt-api</code> classloading, and then
<code>*Builder</code>s are created via standard instantiation using the
<code>new</code> operator thereafter. This also benefits certain
environments that may not have ideal <code>ClassLoader</code>
implementations (e.g. Tomcat in some cases).</p>
<p><strong>NOTE: because this changes which classes are loaded via
reflection, any environments that must explicitly reference reflective
class names (e.g. GraalVM applications) will need to be updated to
reflect the new factory class names</strong>.</p>
<p>See <a href="https://redirect.github.com/jwtk/jjwt/issues/988">Issue
988</a>.</p>
</li>
<li>
<p>Upgrades the Gson dependency to <code>2.11.0</code></p>
</li>
<li>
<p>Upgrades the BouncyCastle dependency to <code>1.78.1</code></p>
</li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/sigpwned"><code>@​sigpwned</code></a>
made their first contribution in <a
href="https://redirect.github.com/jwtk/jjwt/pull/968">jwtk/jjwt#968</a></li>
<li><a
href="https://github.com/TheMrMilchmann"><code>@​TheMrMilchmann</code></a>
made their first contribution in <a
href="https://redirect.github.com/jwtk/jjwt/pull/979">jwtk/jjwt#979</a></li>
<li><a href="https://github.com/atanasg"><code>@​atanasg</code></a> made
their first contribution in <a
href="https://redirect.github.com/jwtk/jjwt/pull/974">jwtk/jjwt#974</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/jwtk/jjwt/compare/0.12.6...0.12.7">https://github.com/jwtk/jjwt/compare/0.12.6...0.12.7</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/jwtk/jjwt/blob/master/CHANGELOG.md">io.jsonwebtoken:jjwt-api's
changelog</a>.</em></p>
<blockquote>
<h3>0.12.7</h3>
<p>This patch release:</p>
<ul>
<li>
<p>Adds a new Maven BOM, useful for multi-module projects. See <a
href="https://redirect.github.com/jwtk/jjwt/issues/967">Issue
967</a>.</p>
</li>
<li>
<p>Allows the <code>JwtParserBuilder</code> to have empty nested
algorithm collections, effectively disabling the parser's associated
feature:</p>
<ul>
<li>Emptying the <code>zip()</code> nested collection disables JWT
decompression.</li>
<li>Emptying the <code>sig()</code> nested collection disables JWS
mac/signature verification (i.e. all JWSs will be
unsupported/rejected).</li>
<li>Emptying either the <code>enc()</code> or <code>key()</code> nested
collections disables JWE decryption (i.e. all JWEs will be
unsupported/rejected)</li>
</ul>
<p>See <a href="https://redirect.github.com/jwtk/jjwt/issues/996">Issue
996</a>.</p>
</li>
<li>
<p>Fixes <a href="https://redirect.github.com/jwtk/jjwt/issues/961">bug
961</a> where <code>JwtParserBuilder</code> nested collection builders
were not correctly replacing algorithms with the same id.</p>
</li>
<li>
<p>Ensures a <code>JwkSet</code>'s <code>keys</code> collection is no
longer entirely secret/redacted by default. This was an overzealous
default that was unnecessarily restrictive; the <code>keys</code>
collection itself should always be public, and each individual key
within should determine which fields should be redacted when printed.
See <a href="https://redirect.github.com/jwtk/jjwt/issues/976">Issue
976</a>.</p>
</li>
<li>
<p>Improves performance slightly by ensuring all <code>jjwt-api</code>
utility methods that create <code>*Builder</code> instances
(<code>Jwts.builder()</code>, <code>Jwts.parserBuilder()</code>,
<code>Jwks.builder()</code>, etc) no longer use reflection.</p>
<p>Instead,<code>static</code> factories are created via reflection only
once during initial <code>jjwt-api</code> classloading, and then
<code>*Builder</code>s are created via standard instantiation using the
<code>new</code> operator thereafter. This also benefits certain
environments that may not have ideal <code>ClassLoader</code>
implementations (e.g. Tomcat in some cases).</p>
<p><strong>NOTE: because this changes which classes are loaded via
reflection, any environments that must explicitly reference reflective
class names (e.g. GraalVM applications) will need to be updated to
reflect the new factory class names</strong>.</p>
<p>See <a href="https://redirect.github.com/jwtk/jjwt/issues/988">Issue
988</a>.</p>
</li>
<li>
<p>Upgrades the Gson dependency to <code>2.11.0</code></p>
</li>
<li>
<p>Upgrades the BouncyCastle dependency to <code>1.78.1</code></p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/jwtk/jjwt/commit/77aeda012c4e31b86fb66acf43a67775c6fa3142"><code>77aeda0</code></a>
[maven-release-plugin] prepare release 0.12.7</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/47d966f8e93734cf35fc19f5c1a9e5cc4abe624b"><code>47d966f</code></a>
Testing latest sonatype central publishing guidelines</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/22ca29fe8849b11d2793bfcf2825ef692f2c19b2"><code>22ca29f</code></a>
[maven-release-plugin] rollback the release of 0.12.7</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/0487f9b49f10f37b7ad5b4e664f3e9b9a25e4a1c"><code>0487f9b</code></a>
[maven-release-plugin] prepare for next development iteration</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/4329125bac91880cb852983b1475465c30a1d819"><code>4329125</code></a>
[maven-release-plugin] prepare release 0.12.7</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/0ddc51421240a9832f38c9afd966429c6d1aeb19"><code>0ddc514</code></a>
- Ensured JJWT_RELEASE_VERSION placeholders reference 0.12.7</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/efed1cf56f9b9715e60eaac7fda6b2c4b62410b9"><code>efed1cf</code></a>
Updated 0.12.7 change list</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/ca27b122b7f44f3bdd4cd4f636d084f38cc3b3c8"><code>ca27b12</code></a>
Resolves <a
href="https://redirect.github.com/jwtk/jjwt/issues/1010">#1010</a> (<a
href="https://redirect.github.com/jwtk/jjwt/issues/1011">#1011</a>)</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/55c7b9adef88328f59534f232060830c34f25478"><code>55c7b9a</code></a>
Resolves <a
href="https://redirect.github.com/jwtk/jjwt/issues/771">#771</a> (<a
href="https://redirect.github.com/jwtk/jjwt/issues/1009">#1009</a>)</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/6e9c6a5a825c5ec38f90006f48cc1f8640a6d82e"><code>6e9c6a5</code></a>
Bump org.bouncycastle:bcpkix-jdk18on from 1.78 to 1.78.1 (<a
href="https://redirect.github.com/jwtk/jjwt/issues/1008">#1008</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/jwtk/jjwt/compare/0.12.6...0.12.7">compare
view</a></li>
</ul>
</details>
<br />

Updates `io.jsonwebtoken:jjwt-impl` from 0.12.6 to 0.12.7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jwtk/jjwt/releases">io.jsonwebtoken:jjwt-impl's
releases</a>.</em></p>
<blockquote>
<h2>0.12.7</h2>
<p>This patch release:</p>
<ul>
<li>
<p>Adds a new Maven BOM! This is useful for multi-module projects. See
<a href="https://redirect.github.com/jwtk/jjwt/issues/967">Issue
967</a>.</p>
</li>
<li>
<p>Allows the <code>JwtParserBuilder</code> to have empty nested
algorithm collections, effectively disabling the parser's associated
feature:</p>
<ul>
<li>Emptying the <code>zip()</code> nested collection disables JWT
decompression.</li>
<li>Emptying the <code>sig()</code> nested collection disables JWS
mac/signature verification (i.e. all JWSs will be
unsupported/rejected).</li>
<li>Emptying either the <code>enc()</code> or <code>key()</code> nested
collections disables JWE decryption (i.e. all JWEs will be
unsupported/rejected)</li>
</ul>
<p>See <a href="https://redirect.github.com/jwtk/jjwt/issues/996">Issue
996</a>.</p>
</li>
<li>
<p>Fixes <a href="https://redirect.github.com/jwtk/jjwt/issues/961">bug
961</a> where <code>JwtParserBuilder</code> nested collection builders
were not correctly replacing algorithms with the same id.</p>
</li>
<li>
<p>Ensures a <code>JwkSet</code>'s <code>keys</code> collection is no
longer entirely secret/redacted by default. This was an overzealous
default that was unnecessarily restrictive; the <code>keys</code>
collection itself should always be public, and each individual key
within should determine which fields should be redacted when printed.
See <a href="https://redirect.github.com/jwtk/jjwt/issues/976">Issue
976</a>.</p>
</li>
<li>
<p>Improves performance slightly by ensuring all <code>jjwt-api</code>
utility methods that create <code>*Builder</code> instances
(<code>Jwts.builder()</code>, <code>Jwts.parserBuilder()</code>,
<code>Jwks.builder()</code>, etc) no longer use reflection.</p>
<p>Instead,<code>static</code> factories are created via reflection only
once during initial <code>jjwt-api</code> classloading, and then
<code>*Builder</code>s are created via standard instantiation using the
<code>new</code> operator thereafter. This also benefits certain
environments that may not have ideal <code>ClassLoader</code>
implementations (e.g. Tomcat in some cases).</p>
<p><strong>NOTE: because this changes which classes are loaded via
reflection, any environments that must explicitly reference reflective
class names (e.g. GraalVM applications) will need to be updated to
reflect the new factory class names</strong>.</p>
<p>See <a href="https://redirect.github.com/jwtk/jjwt/issues/988">Issue
988</a>.</p>
</li>
<li>
<p>Upgrades the Gson dependency to <code>2.11.0</code></p>
</li>
<li>
<p>Upgrades the BouncyCastle dependency to <code>1.78.1</code></p>
</li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/sigpwned"><code>@​sigpwned</code></a>
made their first contribution in <a
href="https://redirect.github.com/jwtk/jjwt/pull/968">jwtk/jjwt#968</a></li>
<li><a
href="https://github.com/TheMrMilchmann"><code>@​TheMrMilchmann</code></a>
made their first contribution in <a
href="https://redirect.github.com/jwtk/jjwt/pull/979">jwtk/jjwt#979</a></li>
<li><a href="https://github.com/atanasg"><code>@​atanasg</code></a> made
their first contribution in <a
href="https://redirect.github.com/jwtk/jjwt/pull/974">jwtk/jjwt#974</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/jwtk/jjwt/compare/0.12.6...0.12.7">https://github.com/jwtk/jjwt/compare/0.12.6...0.12.7</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/jwtk/jjwt/blob/master/CHANGELOG.md">io.jsonwebtoken:jjwt-impl's
changelog</a>.</em></p>
<blockquote>
<h3>0.12.7</h3>
<p>This patch release:</p>
<ul>
<li>
<p>Adds a new Maven BOM, useful for multi-module projects. See <a
href="https://redirect.github.com/jwtk/jjwt/issues/967">Issue
967</a>.</p>
</li>
<li>
<p>Allows the <code>JwtParserBuilder</code> to have empty nested
algorithm collections, effectively disabling the parser's associated
feature:</p>
<ul>
<li>Emptying the <code>zip()</code> nested collection disables JWT
decompression.</li>
<li>Emptying the <code>sig()</code> nested collection disables JWS
mac/signature verification (i.e. all JWSs will be
unsupported/rejected).</li>
<li>Emptying either the <code>enc()</code> or <code>key()</code> nested
collections disables JWE decryption (i.e. all JWEs will be
unsupported/rejected)</li>
</ul>
<p>See <a href="https://redirect.github.com/jwtk/jjwt/issues/996">Issue
996</a>.</p>
</li>
<li>
<p>Fixes <a href="https://redirect.github.com/jwtk/jjwt/issues/961">bug
961</a> where <code>JwtParserBuilder</code> nested collection builders
were not correctly replacing algorithms with the same id.</p>
</li>
<li>
<p>Ensures a <code>JwkSet</code>'s <code>keys</code> collection is no
longer entirely secret/redacted by default. This was an overzealous
default that was unnecessarily restrictive; the <code>keys</code>
collection itself should always be public, and each individual key
within should determine which fields should be redacted when printed.
See <a href="https://redirect.github.com/jwtk/jjwt/issues/976">Issue
976</a>.</p>
</li>
<li>
<p>Improves performance slightly by ensuring all <code>jjwt-api</code>
utility methods that create <code>*Builder</code> instances
(<code>Jwts.builder()</code>, <code>Jwts.parserBuilder()</code>,
<code>Jwks.builder()</code>, etc) no longer use reflection.</p>
<p>Instead,<code>static</code> factories are created via reflection only
once during initial <code>jjwt-api</code> classloading, and then
<code>*Builder</code>s are created via standard instantiation using the
<code>new</code> operator thereafter. This also benefits certain
environments that may not have ideal <code>ClassLoader</code>
implementations (e.g. Tomcat in some cases).</p>
<p><strong>NOTE: because this changes which classes are loaded via
reflection, any environments that must explicitly reference reflective
class names (e.g. GraalVM applications) will need to be updated to
reflect the new factory class names</strong>.</p>
<p>See <a href="https://redirect.github.com/jwtk/jjwt/issues/988">Issue
988</a>.</p>
</li>
<li>
<p>Upgrades the Gson dependency to <code>2.11.0</code></p>
</li>
<li>
<p>Upgrades the BouncyCastle dependency to <code>1.78.1</code></p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/jwtk/jjwt/commit/77aeda012c4e31b86fb66acf43a67775c6fa3142"><code>77aeda0</code></a>
[maven-release-plugin] prepare release 0.12.7</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/47d966f8e93734cf35fc19f5c1a9e5cc4abe624b"><code>47d966f</code></a>
Testing latest sonatype central publishing guidelines</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/22ca29fe8849b11d2793bfcf2825ef692f2c19b2"><code>22ca29f</code></a>
[maven-release-plugin] rollback the release of 0.12.7</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/0487f9b49f10f37b7ad5b4e664f3e9b9a25e4a1c"><code>0487f9b</code></a>
[maven-release-plugin] prepare for next development iteration</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/4329125bac91880cb852983b1475465c30a1d819"><code>4329125</code></a>
[maven-release-plugin] prepare release 0.12.7</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/0ddc51421240a9832f38c9afd966429c6d1aeb19"><code>0ddc514</code></a>
- Ensured JJWT_RELEASE_VERSION placeholders reference 0.12.7</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/efed1cf56f9b9715e60eaac7fda6b2c4b62410b9"><code>efed1cf</code></a>
Updated 0.12.7 change list</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/ca27b122b7f44f3bdd4cd4f636d084f38cc3b3c8"><code>ca27b12</code></a>
Resolves <a
href="https://redirect.github.com/jwtk/jjwt/issues/1010">#1010</a> (<a
href="https://redirect.github.com/jwtk/jjwt/issues/1011">#1011</a>)</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/55c7b9adef88328f59534f232060830c34f25478"><code>55c7b9a</code></a>
Resolves <a
href="https://redirect.github.com/jwtk/jjwt/issues/771">#771</a> (<a
href="https://redirect.github.com/jwtk/jjwt/issues/1009">#1009</a>)</li>
<li><a
href="https://github.com/jwtk/jjwt/commit/6e9c6a5a825c5ec38f90006f48cc1f8640a6d82e"><code>6e9c6a5</code></a>
Bump org.bouncycastle:bcpkix-jdk18on from 1.78 to 1.78.1 (<a
href="https://redirect.github.com/jwtk/jjwt/issues/1008">#1008</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/jwtk/jjwt/compare/0.12.6...0.12.7">compare
view</a></li>
</ul>
</details>
<br />

Updates `io.jsonwebtoken:jjwt-jackson` from 0.12.6 to 0.12.7


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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-20 15:34:11 +01:00
dependabot[bot] fbee4b99e4 build(deps): bump actions/dependency-review-action from 4.7.1 to 4.7.2 (#4230)
Bumps
[actions/dependency-review-action](https://github.com/actions/dependency-review-action)
from 4.7.1 to 4.7.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/dependency-review-action/releases">actions/dependency-review-action's
releases</a>.</em></p>
<blockquote>
<h2>4.7.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Add Missing Languages to CodeQL Advanced Configuration by <a
href="https://github.com/KyFaSt"><code>@​KyFaSt</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/945">actions/dependency-review-action#945</a></li>
<li>Deprecate deny lists by <a
href="https://github.com/claire153"><code>@​claire153</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/958">actions/dependency-review-action#958</a></li>
<li>Address discrepancy between docs and reality by <a
href="https://github.com/ahpook"><code>@​ahpook</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/960">actions/dependency-review-action#960</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/KyFaSt"><code>@​KyFaSt</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/945">actions/dependency-review-action#945</a></li>
<li><a href="https://github.com/claire153"><code>@​claire153</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/958">actions/dependency-review-action#958</a></li>
<li><a href="https://github.com/ahpook"><code>@​ahpook</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/960">actions/dependency-review-action#960</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/dependency-review-action/compare/v4...v4.7.2">https://github.com/actions/dependency-review-action/compare/v4...v4.7.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/dependency-review-action/commit/bc41886e18ea39df68b1b1245f4184881938e050"><code>bc41886</code></a>
Cut 4.7.2 version release (<a
href="https://redirect.github.com/actions/dependency-review-action/issues/964">#964</a>)</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/1c73553e364351d71bdd9718e92c824e1d39aaf1"><code>1c73553</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/dependency-review-action/issues/960">#960</a>
from ahpook/ahpook/address-docs-dashes</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/fac3d41a588e61d27618248093f9c9137e20527c"><code>fac3d41</code></a>
Bump the minor-updates group across 1 directory with 5 updates (<a
href="https://redirect.github.com/actions/dependency-review-action/issues/956">#956</a>)</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/d8073c4b76cb44bb87b02d4facf11c298317533b"><code>d8073c4</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/dependency-review-action/issues/958">#958</a>
from actions/claire153/deprecate-deny-lists</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/77184c6339b69987ba61f2fd650e0facc7bd2637"><code>77184c6</code></a>
Fix tests</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/5558c35bb3e79ef0a0f2d9896a56060e24df9bea"><code>5558c35</code></a>
Address discrepancy between docs and reality</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/e85d57a50e73c596b97dac69d8b3ed1a110c8bbf"><code>e85d57a</code></a>
Remove test code</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/3eb62794c5d48f3f51627b823b3efad8c224aafb"><code>3eb6279</code></a>
Re-add test package. Only show warning in summary if option is used.
Update c...</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/7cf33ac2f2d46e957b8c2df562c806d68486ab80"><code>7cf33ac</code></a>
Remove test deny list</li>
<li><a
href="https://github.com/actions/dependency-review-action/commit/493bee056051bfd97929ad42f88aa2422bd19196"><code>493bee0</code></a>
Remove test package</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/dependency-review-action/compare/da24556b548a50705dd671f47852072ea4c105d9...bc41886e18ea39df68b1b1245f4184881938e050">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/dependency-review-action&package-manager=github_actions&previous-version=4.7.1&new-version=4.7.2)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-20 15:33:56 +01:00
Ludy 28b1b96cfb feat(audit): introduce structured Audit API with export, stats, and cleanup endpoints (#4217)
# Description of Changes

- Added new REST-based `AuditDashboardController` under `/api/v1/audit`
with endpoints for:
  - Audit data retrieval with pagination (`/data`)
  - Statistics retrieval (`/stats`)
  - Export in CSV and JSON (`/export/csv`, `/export/json`)
  - Cleanup of audit events before a given date (`/cleanup/before`)
  - Retrieval of distinct audit event types (`/types`)
- Extracted web dashboard logic into `AuditDashboardWebController` (view
rendering only).
- Introduced new API models:
  - `AuditDataRequest`, `AuditDataResponse`
  - `AuditExportRequest`, `AuditDateExportRequest`
  - `AuditStatsResponse`
- Extended `PersistentAuditEventRepository` with richer query methods
(histograms, counts, top/latest events, distinct principals).
- Updated `dashboard.js` to use new API endpoints under `/api/v1/audit`.
- Enhanced authentication handlers and user endpoints with `@Audited`
annotations for login/logout/password change events.
- Cleaned up `LicenseKeyChecker` by removing unused `updateLicenseKey`
method.
- Moved admin-related controllers into `controller.api` namespace with
proper OpenAPI annotations (`@Operation`, `@Tag`).
- Improved `CleanUrlInterceptor` whitelist for new query parameters
(`days`, `date`).

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-18 12:03:57 +01:00
d23c2eaa30 feat: Auto-redact to support text removal on True PDFs/non-custom encoded PDFs, JUnit tests for RedactController, and TextFinder (#3936)
# Description of Changes

## Overview

This enhancement adds **true PDF text removal** to RedactController. It
changes auto-redaction from visual covering to actual text removal. The
feature removes text from True PDFs completely while keeping
compatibility with other PDF types.

## Features

### 1. True PDF Text Removal

- Removes text from PDF structure instead of just hiding it
- No impact to manual redaction or other types of PDFs (e.g.: to
searchable PDFs or custom encoded PDFs)

### 2. Advanced Content Stream Processing

#### How It Works (only high level overview)
- Token Processing: Breaks PDF content into small pieces for exact text
finding
- Font Tracking: Keeps track of fonts and formatting
- Text Operators: Finds PDF commands that show text (`Tj`, `TJ`, `'`,
`"`)
- Position Mapping: Maps text to exact locations for removal
- Rebuilds PDF: Rebuilds PDFs without the text, while keeping formatting
operators

#### No change for other types PDFs

- Because the iteration through the PDF for token/text removal and for
box placing are two separate completely methods
- This means when the there is custom encoded PDF the token/text removal
won't find any text to remove (because there is no logic for decoding
for, for now) but the box finding methods still reliably finds redacted
words and puts a box onto them. So no change.

### 3. Enhanced TextFinder Integration

#### Minor Improvements
- Page Grouping: Groups found text by page for faster processing

### JUnit tests for both of files.

- Added JUnit tests for both files. 
- Might need future improvement.

### TODOs

- Support for additional PDF types besides true PDFs (currently a WIP),
e.g.: searchable PDF/custom encoded PDF
- Feature to be expected in few weeks (best case scenario, and only if I
succeed), sadly that is significantly harder task so only true PDFs for
now

### UI

- No UI change for now

### Sample files:


[Free_Test_Data_500KB_PDF_redacted.pdf](https://github.com/user-attachments/files/21195841/Free_Test_Data_500KB_PDF_redacted.pdf)

[lorem-ipsum_redacted.pdf](https://github.com/user-attachments/files/21195842/lorem-ipsum_redacted.pdf)

[true-pdf-sample-1_redacted.pdf](https://github.com/user-attachments/files/21195843/true-pdf-sample-1_redacted.pdf)

[true-pdf-sample-2_redacted.pdf](https://github.com/user-attachments/files/21195844/true-pdf-sample-2_redacted.pdf)

[true-pdf-sample-3_redacted.pdf](https://github.com/user-attachments/files/21195845/true-pdf-sample-3_redacted.pdf)


Closes: does not actually close any issues, since it only works with
true PDFs

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2025-08-13 22:52:06 +01:00
stirlingbot[bot] 12ad8211fe Update 3rd Party Licenses (#4184)
Auto-generated by stirlingbot[bot]

Signed-off-by: stirlingbot[bot] <stirlingbot[bot]@users.noreply.github.com>
Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2025-08-11 14:18:27 +01:00
stirlingbot[bot] b41230db53 🤖 format everything with pre-commit by stirlingbot (#4175)
Auto-generated by [create-pull-request][1] with **stirlingbot**

[1]: https://github.com/peter-evans/create-pull-request

Signed-off-by: stirlingbot[bot] <stirlingbot[bot]@users.noreply.github.com>
Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2025-08-11 14:14:41 +01:00
albanobattistella 8211fd8dc4 Update messages_it_IT.properties (#4183)
# Description of Changes

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-11 14:13:58 +01:00
dependabot[bot] 0afbd148cd build(deps): bump edu.sc.seis.launch4j from 3.0.7 to 4.0.0 (#4182)
Bumps edu.sc.seis.launch4j from 3.0.7 to 4.0.0.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=edu.sc.seis.launch4j&package-manager=gradle&previous-version=3.0.7&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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-11 14:12:47 +01:00
dependabot[bot] 91b2f5da53 build(deps): bump actions/ai-inference from 1.2.7 to 1.2.8 (#4181)
[//]: # (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 [actions/ai-inference](https://github.com/actions/ai-inference)
from 1.2.7 to 1.2.8.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/ai-inference/releases">actions/ai-inference's
releases</a>.</em></p>
<blockquote>
<h2>v1.2.8</h2>
<h2>What's Changed</h2>
<ul>
<li>Ensure MCP loops output the right response format by <a
href="https://github.com/sgoedecke"><code>@​sgoedecke</code></a> in <a
href="https://redirect.github.com/actions/ai-inference/pull/89">actions/ai-inference#89</a></li>
<li>Force exit once inference finishes by <a
href="https://github.com/sgoedecke"><code>@​sgoedecke</code></a> in <a
href="https://redirect.github.com/actions/ai-inference/pull/88">actions/ai-inference#88</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/ai-inference/compare/v1...v1.2.8">https://github.com/actions/ai-inference/compare/v1...v1.2.8</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/ai-inference/commit/b81b2afb8390ee6839b494a404766bef6493c7d9"><code>b81b2af</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/ai-inference/issues/88">#88</a>
from actions/sgoedecke/force-exit-once-inference-finishes</li>
<li><a
href="https://github.com/actions/ai-inference/commit/9133f813307a2b02458ed619b7c644316a378541"><code>9133f81</code></a>
package</li>
<li><a
href="https://github.com/actions/ai-inference/commit/7923b92ef8460464ee4eb8f8975a727234fd5509"><code>7923b92</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/ai-inference/issues/89">#89</a>
from actions/sgoedecke/ensure-mcp-loops-output-desired...</li>
<li><a
href="https://github.com/actions/ai-inference/commit/e44da102bfb48b5f86362e4cc7a3550e4c4e2f20"><code>e44da10</code></a>
fixup format parsing</li>
<li><a
href="https://github.com/actions/ai-inference/commit/866ae2b5d7332a2710e5fa066d267fbff1850d38"><code>866ae2b</code></a>
Ensure MCP loops output the right response format</li>
<li><a
href="https://github.com/actions/ai-inference/commit/4685e0dcd41bc58f268df3c4bf86f5dfeca31fc7"><code>4685e0d</code></a>
Force exit once inference finishes in case we are holding any
connections open</li>
<li>See full diff in <a
href="https://github.com/actions/ai-inference/compare/0cbed4a10641c75090de5968e66d70eb4660f751...b81b2afb8390ee6839b494a404766bef6493c7d9">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/ai-inference&package-manager=github_actions&previous-version=1.2.7&new-version=1.2.8)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-11 14:09:47 +01:00
dependabot[bot] 1dd5e9c649 build(deps): bump actions/checkout from 4.2.2 to 4.3.0 (#4180)
[//]: # (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 [actions/checkout](https://github.com/actions/checkout) from 4.2.2
to 4.3.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v4.3.0</h2>
<h2>What's Changed</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
<li>Prepare release v4.3.0 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2237">actions/checkout#2237</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/motss"><code>@​motss</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li><a href="https://github.com/mouismail"><code>@​mouismail</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li><a href="https://github.com/benwells"><code>@​benwells</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li><a href="https://github.com/nebuk89"><code>@​nebuk89</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li><a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4...v4.3.0">https://github.com/actions/checkout/compare/v4...v4.3.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>V4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>v4.2.0</h2>
<ul>
<li>Add Ref and Commit outputs by <a
href="https://github.com/lucacome"><code>@​lucacome</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li>
<li>Dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>- <a
href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>,
<a
href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li>
</ul>
<h2>v4.1.7</h2>
<ul>
<li>Bump the minor-npm-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li>
<li>Check out other refs/* by commit by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li>
<li>Pin actions/checkout's own workflows to a known, good, stable
version. by <a href="https://github.com/jww3"><code>@​jww3</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1776">actions/checkout#1776</a></li>
</ul>
<h2>v4.1.6</h2>
<ul>
<li>Check platform to set archive extension appropriately by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1732">actions/checkout#1732</a></li>
</ul>
<h2>v4.1.5</h2>
<ul>
<li>Update NPM dependencies by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1703">actions/checkout#1703</a></li>
<li>Bump github/codeql-action from 2 to 3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1694">actions/checkout#1694</a></li>
<li>Bump actions/setup-node from 1 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1696">actions/checkout#1696</a></li>
<li>Bump actions/upload-artifact from 2 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1695">actions/checkout#1695</a></li>
<li>README: Suggest <code>user.email</code> to be
<code>41898282+github-actions[bot]@users.noreply.github.com</code> by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1707">actions/checkout#1707</a></li>
</ul>
<h2>v4.1.4</h2>
<ul>
<li>Disable <code>extensions.worktreeConfig</code> when disabling
<code>sparse-checkout</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1692">actions/checkout#1692</a></li>
<li>Add dependabot config by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1688">actions/checkout#1688</a></li>
<li>Bump the minor-actions-dependencies group with 2 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1693">actions/checkout#1693</a></li>
<li>Bump word-wrap from 1.2.3 to 1.2.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1643">actions/checkout#1643</a></li>
</ul>
<h2>v4.1.3</h2>
<ul>
<li>Check git version before attempting to disable
<code>sparse-checkout</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1656">actions/checkout#1656</a></li>
<li>Add SSH user parameter by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1685">actions/checkout#1685</a></li>
<li>Update <code>actions/checkout</code> version in
<code>update-main-version.yml</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1650">actions/checkout#1650</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/checkout/commit/08eba0b27e820071cde6df949e0beb9ba4906955"><code>08eba0b</code></a>
Prepare release v4.3.0 (<a
href="https://redirect.github.com/actions/checkout/issues/2237">#2237</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/631c7dc4f80f88219c5ee78fee08c6b62fac8da1"><code>631c7dc</code></a>
Update package dependencies (<a
href="https://redirect.github.com/actions/checkout/issues/2236">#2236</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/8edcb1bdb4e267140fa742c62e395cd74f332709"><code>8edcb1b</code></a>
Update CODEOWNERS for actions (<a
href="https://redirect.github.com/actions/checkout/issues/2224">#2224</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/09d2acae674a48949e3602304ab46fd20ae0c42f"><code>09d2aca</code></a>
Update README.md (<a
href="https://redirect.github.com/actions/checkout/issues/2194">#2194</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/85e6279cec87321a52edac9c87bce653a07cf6c2"><code>85e6279</code></a>
Adjust positioning of user email note and permissions heading (<a
href="https://redirect.github.com/actions/checkout/issues/2044">#2044</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/009b9ae9e446ad8d9b8c809870b0fbcc5e03573e"><code>009b9ae</code></a>
Documentation update - add recommended permissions to Readme (<a
href="https://redirect.github.com/actions/checkout/issues/2043">#2043</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/cbb722410c2e876e24abbe8de2cc27693e501dcb"><code>cbb7224</code></a>
Update README.md (<a
href="https://redirect.github.com/actions/checkout/issues/1977">#1977</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/3b9b8c884f6b4bb4d5be2779c26374abadae0871"><code>3b9b8c8</code></a>
docs: update README.md (<a
href="https://redirect.github.com/actions/checkout/issues/1971">#1971</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/checkout/compare/11bd71901bbe5b1630ceea73d27597364c9af683...08eba0b27e820071cde6df949e0beb9ba4906955">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.2.2&new-version=4.3.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-11 14:09:30 +01:00
dependabot[bot] 2c293d2231 build(deps): bump actions/download-artifact from 4.3.0 to 5.0.0 (#4179)
Bumps
[actions/download-artifact](https://github.com/actions/download-artifact)
from 4.3.0 to 5.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/download-artifact/releases">actions/download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/407">actions/download-artifact#407</a></li>
<li>BREAKING fix: inconsistent path behavior for single artifact
downloads by ID by <a
href="https://github.com/GrantBirki"><code>@​GrantBirki</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/416">actions/download-artifact#416</a></li>
</ul>
<h2>v5.0.0</h2>
<h3>🚨 Breaking Change</h3>
<p>This release fixes an inconsistency in path behavior for single
artifact downloads by ID. <strong>If you're downloading single artifacts
by ID, the output path may change.</strong></p>
<h4>What Changed</h4>
<p>Previously, <strong>single artifact downloads</strong> behaved
differently depending on how you specified the artifact:</p>
<ul>
<li><strong>By name</strong>: <code>name: my-artifact</code> → extracted
to <code>path/</code> (direct)</li>
<li><strong>By ID</strong>: <code>artifact-ids: 12345</code> → extracted
to <code>path/my-artifact/</code> (nested)</li>
</ul>
<p>Now both methods are consistent:</p>
<ul>
<li><strong>By name</strong>: <code>name: my-artifact</code> → extracted
to <code>path/</code> (unchanged)</li>
<li><strong>By ID</strong>: <code>artifact-ids: 12345</code> → extracted
to <code>path/</code> (fixed - now direct)</li>
</ul>
<h4>Migration Guide</h4>
<h5> No Action Needed If:</h5>
<ul>
<li>You download artifacts by <strong>name</strong></li>
<li>You download <strong>multiple</strong> artifacts by ID</li>
<li>You already use <code>merge-multiple: true</code> as a
workaround</li>
</ul>
<h5>⚠️ Action Required If:</h5>
<p>You download <strong>single artifacts by ID</strong> and your
workflows expect the nested directory structure.</p>
<p><strong>Before v5 (nested structure):</strong></p>
<pre lang="yaml"><code>- uses: actions/download-artifact@v4
  with:
    artifact-ids: 12345
    path: dist
# Files were in: dist/my-artifact/
</code></pre>
<blockquote>
<p>Where <code>my-artifact</code> is the name of the artifact you
previously uploaded</p>
</blockquote>
<p><strong>To maintain old behavior (if needed):</strong></p>
<pre lang="yaml"><code>&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/download-artifact/commit/634f93cb2916e3fdff6788551b99b062d0335ce0"><code>634f93c</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/416">#416</a>
from actions/single-artifact-id-download-path</li>
<li><a
href="https://github.com/actions/download-artifact/commit/b19ff4302770b82aa4694b63703b547756dacce6"><code>b19ff43</code></a>
refactor: resolve download path correctly in artifact download tests
(mainly ...</li>
<li><a
href="https://github.com/actions/download-artifact/commit/e262cbee4ab8c473c61c59a81ad8e9dc760e90db"><code>e262cbe</code></a>
bundle dist</li>
<li><a
href="https://github.com/actions/download-artifact/commit/bff23f9308ceb2f06d673043ea6311519be6a87b"><code>bff23f9</code></a>
update docs</li>
<li><a
href="https://github.com/actions/download-artifact/commit/fff8c148a8fdd56aa81fcb019f0b5f6c65700c4d"><code>fff8c14</code></a>
fix download path logic when downloading a single artifact by id</li>
<li><a
href="https://github.com/actions/download-artifact/commit/448e3f862ab3ef47aa50ff917776823c9946035b"><code>448e3f8</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/407">#407</a>
from actions/nebuk89-patch-1</li>
<li><a
href="https://github.com/actions/download-artifact/commit/47225c44b359a5155efdbbbc352041b3e249fb1b"><code>47225c4</code></a>
Update README.md</li>
<li>See full diff in <a
href="https://github.com/actions/download-artifact/compare/d3f86a106a0bac45b974a628896c90dbdf5c8093...634f93cb2916e3fdff6788551b99b062d0335ce0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/download-artifact&package-manager=github_actions&previous-version=4.3.0&new-version=5.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-11 14:09:19 +01:00
dependabot[bot] 84142bb42a build(deps): bump github/codeql-action from 3.29.7 to 3.29.8 (#4178)
[//]: # (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 [github/codeql-action](https://github.com/github/codeql-action)
from 3.29.7 to 3.29.8.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action's
releases</a>.</em></p>
<blockquote>
<h2>v3.29.8</h2>
<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>3.29.8 - 08 Aug 2025</h2>
<ul>
<li>Fix an issue where the Action would autodetect unsupported languages
such as HTML. <a
href="https://redirect.github.com/github/codeql-action/pull/3015">#3015</a></li>
</ul>
<p>See the full <a
href="https://github.com/github/codeql-action/blob/v3.29.8/CHANGELOG.md">CHANGELOG.md</a>
for more information.</p>
</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'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>3.29.8 - 08 Aug 2025</h2>
<ul>
<li>Fix an issue where the Action would autodetect unsupported languages
such as HTML. <a
href="https://redirect.github.com/github/codeql-action/pull/3015">#3015</a></li>
</ul>
<h2>3.29.7 - 07 Aug 2025</h2>
<p>This release rolls back 3.29.6 to address issues with language
autodetection. It is identical to 3.29.5.</p>
<h2>3.29.6 - 07 Aug 2025</h2>
<ul>
<li>The <code>cleanup-level</code> input to the <code>analyze</code>
Action is now deprecated. The CodeQL Action has written a limited amount
of intermediate results to the database since version 2.2.5, and now
automatically manages cleanup. <a
href="https://redirect.github.com/github/codeql-action/pull/2999">#2999</a></li>
<li>Update default CodeQL bundle version to 2.22.3. <a
href="https://redirect.github.com/github/codeql-action/pull/3000">#3000</a></li>
</ul>
<h2>3.29.5 - 29 Jul 2025</h2>
<ul>
<li>Update default CodeQL bundle version to 2.22.2. <a
href="https://redirect.github.com/github/codeql-action/pull/2986">#2986</a></li>
</ul>
<h2>3.29.4 - 23 Jul 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.3 - 21 Jul 2025</h2>
<p>No user facing changes.</p>
<h2>3.29.2 - 30 Jun 2025</h2>
<ul>
<li>Experimental: When the <code>quality-queries</code> input for the
<code>init</code> action is provided with an argument, separate
<code>.quality.sarif</code> files are produced and uploaded for each
language with the results of the specified queries. Do not use this in
production as it is part of an internal experiment and subject to change
at any time. <a
href="https://redirect.github.com/github/codeql-action/pull/2935">#2935</a></li>
</ul>
<h2>3.29.1 - 27 Jun 2025</h2>
<ul>
<li>Fix bug in PR analysis where user-provided <code>include</code>
query filter fails to exclude non-included queries. <a
href="https://redirect.github.com/github/codeql-action/pull/2938">#2938</a></li>
<li>Update default CodeQL bundle version to 2.22.1. <a
href="https://redirect.github.com/github/codeql-action/pull/2950">#2950</a></li>
</ul>
<h2>3.29.0 - 11 Jun 2025</h2>
<ul>
<li>Update default CodeQL bundle version to 2.22.0. <a
href="https://redirect.github.com/github/codeql-action/pull/2925">#2925</a></li>
<li>Bump minimum CodeQL bundle version to 2.16.6. <a
href="https://redirect.github.com/github/codeql-action/pull/2912">#2912</a></li>
</ul>
<h2>3.28.21 - 28 July 2025</h2>
<p>No user facing changes.</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/76621b61decf072c1cee8dd1ce2d2a82d33c17ed"><code>76621b6</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3019">#3019</a>
from github/update-v3.29.8-679a40d33</li>
<li><a
href="https://github.com/github/codeql-action/commit/29ac3cefbb645d41622f6f9baa1415e06d73cf06"><code>29ac3ce</code></a>
Add release notes for 3.29.7</li>
<li><a
href="https://github.com/github/codeql-action/commit/737cfdebe687c6e720fb99761f23d89751c3b93a"><code>737cfde</code></a>
Update changelog for v3.29.8</li>
<li><a
href="https://github.com/github/codeql-action/commit/679a40d337fedd9b7318253dd72bfe7dc6d1886c"><code>679a40d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3014">#3014</a>
from github/henrymercer/rebuild-dispatch</li>
<li><a
href="https://github.com/github/codeql-action/commit/6fe50b283a3d2e5533299f72d99216cd8815500f"><code>6fe50b2</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3015">#3015</a>
from github/henrymercer/language-autodetection-worka...</li>
<li><a
href="https://github.com/github/codeql-action/commit/6bc91d64f66d435200c8ba85c64878c3cbfad33b"><code>6bc91d6</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/6b4fedca4f3428195d7ba1ca7c7404f9ea472911"><code>6b4fedc</code></a>
Bump Action patch version</li>
<li><a
href="https://github.com/github/codeql-action/commit/5794ffcb4ab0e87e4b8a8446ef048488303db295"><code>5794ffc</code></a>
Fix auto-detection of extractors that aren't languages</li>
<li><a
href="https://github.com/github/codeql-action/commit/bd62bf449cd8695f818546752cc8157693e1716c"><code>bd62bf4</code></a>
Finish in-progress merges</li>
<li><a
href="https://github.com/github/codeql-action/commit/2afb4e6f3c84ec0534284f2b47ae8206dcb401bf"><code>2afb4e6</code></a>
Avoid specifying branch unnecessarily</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/51f77329afa6477de8c49fc9c7046c15b9a4e79d...76621b61decf072c1cee8dd1ce2d2a82d33c17ed">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=3.29.7&new-version=3.29.8)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-11 14:09:09 +01:00
dependabot[bot] bb07eced6e build(deps): bump gradle/actions from 4.4.1 to 4.4.2 (#4177)
Bumps [gradle/actions](https://github.com/gradle/actions) from 4.4.1 to
4.4.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/gradle/actions/releases">gradle/actions's
releases</a>.</em></p>
<blockquote>
<h2>v4.4.2</h2>
<p>This patch release updates a bunch of dependency versions</p>
<h2>What's Changed</h2>
<ul>
<li>Bump github/codeql-action from 3.29.4 to 3.29.5 in the
github-actions group across 1 directory (<a
href="https://redirect.github.com/gradle/actions/pull/703">gradle/actions#703</a>)</li>
<li>Bumps the npm-dependencies group in /sources with 4 updates (<a
href="https://redirect.github.com/gradle/actions/pull/702">gradle/actions#702</a>)</li>
<li>Upgrade to gradle 9 in workflows and tests (<a
href="https://redirect.github.com/gradle/actions/pull/704">gradle/actions#704</a>)</li>
<li>Update known wrapper checksums (<a
href="https://redirect.github.com/gradle/actions/pull/701">gradle/actions#701</a>)</li>
<li>Bump Gradle Wrapper from 8.14.3 to 9.0.0 in
/.github/workflow-samples/gradle-plugin (<a
href="https://redirect.github.com/gradle/actions/pull/695">gradle/actions#695</a>)</li>
<li>Bump Gradle Wrapper from 8.14.3 to 9.0.0 in
/.github/workflow-samples/groovy-dsl (<a
href="https://redirect.github.com/gradle/actions/pull/696">gradle/actions#696</a>)</li>
<li>Bump Gradle Wrapper from 8.14.3 to 9.0.0 in
/.github/workflow-samples/java-toolchain (<a
href="https://redirect.github.com/gradle/actions/pull/697">gradle/actions#697</a>)</li>
<li>Bump com.fasterxml.jackson.dataformat:jackson-dataformat-smile from
2.19.1 to 2.19.2 in /sources/test/init-scripts in the gradle group
across 1 directory (<a
href="https://redirect.github.com/gradle/actions/pull/693">gradle/actions#693</a>)</li>
<li>Bump github/codeql-action from 3.29.0 to 3.29.4 in the
github-actions group across 1 directory (<a
href="https://redirect.github.com/gradle/actions/pull/691">gradle/actions#691</a>)</li>
<li>Bump the npm-dependencies group in /sources with 5 updates (<a
href="https://redirect.github.com/gradle/actions/pull/692">gradle/actions#692</a>)</li>
<li>Bump references to Develocity Gradle plugin from 4.0.2 to 4.1 (<a
href="https://redirect.github.com/gradle/actions/pull/685">gradle/actions#685</a>)</li>
<li>Bump the npm-dependencies group across 1 directory with 8 updates
(<a
href="https://redirect.github.com/gradle/actions/pull/684">gradle/actions#684</a>)</li>
<li>Run Gradle release candidate tests with JDK 17 (<a
href="https://redirect.github.com/gradle/actions/pull/690">gradle/actions#690</a>)</li>
<li>Update Develocity npm agent to version 1.0.1 (<a
href="https://redirect.github.com/gradle/actions/pull/687">gradle/actions#687</a>)</li>
<li>Update known wrapper checksums (<a
href="https://redirect.github.com/gradle/actions/pull/688">gradle/actions#688</a>)</li>
<li>Bump Gradle Wrapper from 8.14.2 to 8.14.3 in
/.github/workflow-samples/kotlin-dsl (<a
href="https://redirect.github.com/gradle/actions/pull/683">gradle/actions#683</a></li>
<li>Bump the github-actions group across 1 directory with 3 updates (<a
href="https://redirect.github.com/gradle/actions/pull/675">gradle/actions#675</a>)</li>
<li>Bump the gradle group across 3 directories with 2 updates (<a
href="https://redirect.github.com/gradle/actions/pull/674">gradle/actions#674</a>)</li>
<li>Bump Gradle Wrapper from 8.14.2 to 8.14.3 in
/sources/test/init-scripts (<a
href="https://redirect.github.com/gradle/actions/pull/679">gradle/actions#679</a>)</li>
<li>Bump Gradle Wrapper from 8.14.2 to 8.14.3 in
/.github/workflow-samples/java-toolchain (<a
href="https://redirect.github.com/gradle/actions/pull/682">gradle/actions#682</a>)</li>
<li>Bump Gradle Wrapper from 8.14.2 to 8.14.3 in
/.github/workflow-samples/groovy-dsl (<a
href="https://redirect.github.com/gradle/actions/pull/681">gradle/actions#681</a>)</li>
<li>Bump Gradle Wrapper from 8.14.2 to 8.14.3 in
/.github/workflow-samples/gradle-plugin (<a
href="https://redirect.github.com/gradle/actions/pull/680">gradle/actions#680</a>)</li>
<li>Update known wrapper checksums (<a
href="https://redirect.github.com/gradle/actions/pull/676">gradle/actions#676</a>)</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/gradle/actions/compare/v4.4.1...v4.4.2">https://github.com/gradle/actions/compare/v4.4.1...v4.4.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/gradle/actions/commit/017a9effdb900e5b5b2fddfb590a105619dca3c3"><code>017a9ef</code></a>
Bump github/codeql-action from 3.29.4 to 3.29.5 in the github-actions
group a...</li>
<li><a
href="https://github.com/gradle/actions/commit/d5397cf4c822cff29ba7b79b2c9ed29917bbe84a"><code>d5397cf</code></a>
Merge branch 'main' into
dependabot/github_actions/github-actions-12d2e1d0cf</li>
<li><a
href="https://github.com/gradle/actions/commit/559dfbd266963f24dd17a76f3ce0f009a6c020ef"><code>559dfbd</code></a>
Bump the npm-dependencies group in /sources with 4 updates (<a
href="https://redirect.github.com/gradle/actions/issues/702">#702</a>)</li>
<li><a
href="https://github.com/gradle/actions/commit/075ee283cc5fba335ac5184eb48b40672919612a"><code>075ee28</code></a>
Merge branch 'main' into
dependabot/npm_and_yarn/sources/npm-dependencies-fda...</li>
<li><a
href="https://github.com/gradle/actions/commit/c3e68c5c72468b5662b0e325d727b1c1e6a14c16"><code>c3e68c5</code></a>
Upgrade to gradle 9 in workflows and tests (<a
href="https://redirect.github.com/gradle/actions/issues/704">#704</a>)</li>
<li><a
href="https://github.com/gradle/actions/commit/d7e674f97b03ec86a7d6f688bd66c45269b35bf1"><code>d7e674f</code></a>
Fix init script tests dependencies</li>
<li><a
href="https://github.com/gradle/actions/commit/3e6512898620556ad8848c4073e8279051eaf7db"><code>3e65128</code></a>
Upgrade init script tests to Gradle 9</li>
<li><a
href="https://github.com/gradle/actions/commit/896b9fa30994e16abfabdffea39f9bbffa8ade46"><code>896b9fa</code></a>
Run tests on Gradle release candidate and current with JDK 17 as
required sin...</li>
<li><a
href="https://github.com/gradle/actions/commit/431b3e39ba5839847f90c3917165b1f0b5b2d0fa"><code>431b3e3</code></a>
Bump github/codeql-action in the github-actions group across 1
directory</li>
<li><a
href="https://github.com/gradle/actions/commit/44c3664945acba910b91b10f41602a5caceb57df"><code>44c3664</code></a>
Bump the npm-dependencies group in /sources with 4 updates</li>
<li>Additional commits viewable in <a
href="https://github.com/gradle/actions/compare/ac638b010cf58a27ee6c972d7336334ccaf61c96...017a9effdb900e5b5b2fddfb590a105619dca3c3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=gradle/actions&package-manager=github_actions&previous-version=4.4.1&new-version=4.4.2)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-08-11 14:08:52 +01:00
stirlingbot[bot] 901218cdb2 🌐 Sync Translations + Update README Progress Table (#4174)
### Description of Changes

This Pull Request was automatically generated to synchronize updates to
translation files and documentation. Below are the details of the
changes made:

#### **1. Synchronization of Translation Files**
- Updated translation files (`messages_*.properties`) to reflect changes
in the reference file `messages_en_GB.properties`.
- Ensured consistency and synchronization across all supported language
files.
- Highlighted any missing or incomplete translations.

#### **2. Update README.md**
- Generated the translation progress table in `README.md`.
- Added a summary of the current translation status for all supported
languages.
- Included up-to-date statistics on translation coverage.

#### **Why these changes are necessary**
- Keeps translation files aligned with the latest reference updates.
- Ensures the documentation reflects the current translation progress.

---

Auto-generated by [create-pull-request][1].

[1]: https://github.com/peter-evans/create-pull-request

Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2025-08-11 12:29:51 +01:00
6699facc24 JWT Authentication (#3921)
This PR introduces JWT (JSON Web Token) authentication for Stirling-PDF,
allowing for stateless authentication capabilities alongside the
existing session-based authentication system.

### Key Features & Changes

  JWT Authentication System
- Core Service: JwtService.java - Token generation, validation, and
cookie management
- Authentication Filter: JwtAuthenticationFilter.java - Request
interceptor for JWT validation
- Key Management: KeyPersistenceService.java +
KeyPairCleanupService.java - RSA key rotation and persistence
  - Frontend: jwt-init.js - Client-side JWT handling and URL cleanup

  Security Integration
- SAML2: JwtSaml2AuthenticationRequestRepository.java - JWT-backed SAML
request storage
- OAuth2: Updated CustomAuthenticationSuccessHandler. java,
CustomOAuth2AuthenticationSuccessHandler.java &
CustomSaml2AuthenticationSuccessHandler.java for JWT integration
- Configuration: Enhanced SecurityConfiguration.java with JWT filter
chain

  Infrastructure
  - Caching: CacheConfig.java - Caffeine cache for JWT keys
  - Database: New JwtVerificationKey.java entity for key storage
- Error Handling: JwtAuthenticationEntryPoint.java for unauthorized
access

### Challenges Encountered

- Configured SecurityConfiguration to use either
`UsernamePasswordAuthenticationFilter` or `JWTAuthenticationFilter`
based on whether JWTs are enabled to prevent the former intercepting
requests while in stateless mode.
- Removed the `.defaultSuccessUrl("/")` from login configuration as its
inclusion was preventing overriding the use of the
`CustomAuthenticationSuccessHandler` and preventing proper
authentication flows.
---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [x] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [x] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [x] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [x] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
<img width="599" height="515" alt="Screenshot 2025-07-10 at 13 35 56"
src="https://github.com/user-attachments/assets/4126b752-ad0d-4ffa-b295-6714c43381e1"
/>

<img width="392" height="376" alt="Screenshot 2025-07-10 at 13 36 10"
src="https://github.com/user-attachments/assets/c681bc43-68ff-4934-8245-d544e2ad7b9c"
/>

<img width="1870" height="986" alt="eb750e8c3954fc47b2dd2e6e76ddb7d5"
src="https://github.com/user-attachments/assets/fca9b23d-b0b6-4884-8a26-98a441b641ef"
/>

<img width="1299" height="702" alt="Screenshot 2025-07-10 at 13 30 57"
src="https://github.com/user-attachments/assets/9415d8bf-fac4-4d38-8c3a-985d043d1076"
/>

### Testing (if applicable)

- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ludy <Ludy87@users.noreply.github.com>
Co-authored-by: EthanHealy01 <80844253+EthanHealy01@users.noreply.github.com>
Co-authored-by: Ethan <ethan@MacBook-Pro.local>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2025-08-11 12:27:42 +01:00
Ludy 74c92ef215 chore(labeler): add new 'v2' label and expand matching rules (#4172)
# Description of Changes

- **Added** a new `v2` label with `base-branch` targeting `V2`
- **Extended** the 'UI' label matching to include `frontend/**` files
- **Extended** the 'Scripts' label matching to include `docker/**` files
- **Removed** duplicate `devTools/.*` entry from 'Devtools' label
configuration

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-08-11 10:26:57 +01:00
687 changed files with 10364 additions and 177353 deletions
+6 -6
View File
@@ -7,12 +7,12 @@
"Bash(grep:*)",
"Bash(cat:*)",
"Bash(find:*)",
"Bash(npm test)",
"Bash(npm test:*)",
"Bash(ls:*)",
"Bash(npx tsc:*)",
"Bash(sed:*)"
"Bash(grep:*)",
"Bash(rg:*)",
"Bash(strings:*)",
"Bash(pkill:*)",
"Bash(true)"
],
"deny": []
}
}
}
+1 -1
View File
@@ -24,7 +24,7 @@ indent_size = 2
insert_final_newline = false
trim_trailing_whitespace = false
[{*.js,*.jsx,*.ts,*.tsx}]
[*.js]
indent_size = 2
[*.css]
+7
View File
@@ -29,3 +29,10 @@ project: &project
- settings.gradle
- frontend/**
- docker/**
- testing/**
frontend: &frontend
- frontend/**
- .github/workflows/testdriver.yml
- testing/**
- docker/**
+8
View File
@@ -0,0 +1,8 @@
pip
setuptools
WeasyPrint
pdf2image
pillow
unoserver
opencv-python-headless
pre-commit
+638
View File
@@ -0,0 +1,638 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile --allow-unsafe --generate-hashes --output-file='.github\scripts\requirements_dev.txt' --strip-extras '.github\scripts\requirements_dev.in'
#
brotli==1.1.0 \
--hash=sha256:03d20af184290887bdea3f0f78c4f737d126c74dc2f3ccadf07e54ceca3bf208 \
--hash=sha256:0541e747cce78e24ea12d69176f6a7ddb690e62c425e01d31cc065e69ce55b48 \
--hash=sha256:069a121ac97412d1fe506da790b3e69f52254b9df4eb665cd42460c837193354 \
--hash=sha256:0737ddb3068957cf1b054899b0883830bb1fec522ec76b1098f9b6e0f02d9419 \
--hash=sha256:0b63b949ff929fbc2d6d3ce0e924c9b93c9785d877a21a1b678877ffbbc4423a \
--hash=sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128 \
--hash=sha256:11d00ed0a83fa22d29bc6b64ef636c4552ebafcef57154b4ddd132f5638fbd1c \
--hash=sha256:141bd4d93984070e097521ed07e2575b46f817d08f9fa42b16b9b5f27b5ac088 \
--hash=sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9 \
--hash=sha256:1ab4fbee0b2d9098c74f3057b2bc055a8bd92ccf02f65944a241b4349229185a \
--hash=sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3 \
--hash=sha256:1b2c248cd517c222d89e74669a4adfa5577e06ab68771a529060cf5a156e9757 \
--hash=sha256:1e9a65b5736232e7a7f91ff3d02277f11d339bf34099a56cdab6a8b3410a02b2 \
--hash=sha256:224e57f6eac61cc449f498cc5f0e1725ba2071a3d4f48d5d9dffba42db196438 \
--hash=sha256:22fc2a8549ffe699bfba2256ab2ed0421a7b8fadff114a3d201794e45a9ff578 \
--hash=sha256:23032ae55523cc7bccb4f6a0bf368cd25ad9bcdcc1990b64a647e7bbcce9cb5b \
--hash=sha256:2333e30a5e00fe0fe55903c8832e08ee9c3b1382aacf4db26664a16528d51b4b \
--hash=sha256:2954c1c23f81c2eaf0b0717d9380bd348578a94161a65b3a2afc62c86467dd68 \
--hash=sha256:2a24c50840d89ded6c9a8fdc7b6ed3692ed4e86f1c4a4a938e1e92def92933e0 \
--hash=sha256:2de9d02f5bda03d27ede52e8cfe7b865b066fa49258cbab568720aa5be80a47d \
--hash=sha256:2feb1d960f760a575dbc5ab3b1c00504b24caaf6986e2dc2b01c09c87866a943 \
--hash=sha256:30924eb4c57903d5a7526b08ef4a584acc22ab1ffa085faceb521521d2de32dd \
--hash=sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409 \
--hash=sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28 \
--hash=sha256:38025d9f30cf4634f8309c6874ef871b841eb3c347e90b0851f63d1ded5212da \
--hash=sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50 \
--hash=sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f \
--hash=sha256:3d7954194c36e304e1523f55d7042c59dc53ec20dd4e9ea9d151f1b62b4415c0 \
--hash=sha256:3ee8a80d67a4334482d9712b8e83ca6b1d9bc7e351931252ebef5d8f7335a547 \
--hash=sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180 \
--hash=sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0 \
--hash=sha256:43ce1b9935bfa1ede40028054d7f48b5469cd02733a365eec8a329ffd342915d \
--hash=sha256:4410f84b33374409552ac9b6903507cdb31cd30d2501fc5ca13d18f73548444a \
--hash=sha256:494994f807ba0b92092a163a0a283961369a65f6cbe01e8891132b7a320e61eb \
--hash=sha256:4d4a848d1837973bf0f4b5e54e3bec977d99be36a7895c61abb659301b02c112 \
--hash=sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc \
--hash=sha256:4f3607b129417e111e30637af1b56f24f7a49e64763253bbc275c75fa887d4b2 \
--hash=sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265 \
--hash=sha256:524f35912131cc2cabb00edfd8d573b07f2d9f21fa824bd3fb19725a9cf06327 \
--hash=sha256:587ca6d3cef6e4e868102672d3bd9dc9698c309ba56d41c2b9c85bbb903cdb95 \
--hash=sha256:58d4b711689366d4a03ac7957ab8c28890415e267f9b6589969e74b6e42225ec \
--hash=sha256:5b3cc074004d968722f51e550b41a27be656ec48f8afaeeb45ebf65b561481dd \
--hash=sha256:5dab0844f2cf82be357a0eb11a9087f70c5430b2c241493fc122bb6f2bb0917c \
--hash=sha256:5e55da2c8724191e5b557f8e18943b1b4839b8efc3ef60d65985bcf6f587dd38 \
--hash=sha256:5eeb539606f18a0b232d4ba45adccde4125592f3f636a6182b4a8a436548b914 \
--hash=sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0 \
--hash=sha256:5fb2ce4b8045c78ebbc7b8f3c15062e435d47e7393cc57c25115cfd49883747a \
--hash=sha256:6172447e1b368dcbc458925e5ddaf9113477b0ed542df258d84fa28fc45ceea7 \
--hash=sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368 \
--hash=sha256:6974f52a02321b36847cd19d1b8e381bf39939c21efd6ee2fc13a28b0d99348c \
--hash=sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0 \
--hash=sha256:6c6e0c425f22c1c719c42670d561ad682f7bfeeef918edea971a79ac5252437f \
--hash=sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451 \
--hash=sha256:7905193081db9bfa73b1219140b3d315831cbff0d8941f22da695832f0dd188f \
--hash=sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8 \
--hash=sha256:7c4855522edb2e6ae7fdb58e07c3ba9111e7621a8956f481c68d5d979c93032e \
--hash=sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248 \
--hash=sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c \
--hash=sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91 \
--hash=sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724 \
--hash=sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7 \
--hash=sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966 \
--hash=sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9 \
--hash=sha256:890b5a14ce214389b2cc36ce82f3093f96f4cc730c1cffdbefff77a7c71f2a97 \
--hash=sha256:89f4988c7203739d48c6f806f1e87a1d96e0806d44f0fba61dba81392c9e474d \
--hash=sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5 \
--hash=sha256:8dadd1314583ec0bf2d1379f7008ad627cd6336625d6679cf2f8e67081b83acf \
--hash=sha256:901032ff242d479a0efa956d853d16875d42157f98951c0230f69e69f9c09bac \
--hash=sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b \
--hash=sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951 \
--hash=sha256:919e32f147ae93a09fe064d77d5ebf4e35502a8df75c29fb05788528e330fe74 \
--hash=sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648 \
--hash=sha256:929811df5462e182b13920da56c6e0284af407d1de637d8e536c5cd00a7daf60 \
--hash=sha256:949f3b7c29912693cee0afcf09acd6ebc04c57af949d9bf77d6101ebb61e388c \
--hash=sha256:a090ca607cbb6a34b0391776f0cb48062081f5f60ddcce5d11838e67a01928d1 \
--hash=sha256:a1fd8a29719ccce974d523580987b7f8229aeace506952fa9ce1d53a033873c8 \
--hash=sha256:a37b8f0391212d29b3a91a799c8e4a2855e0576911cdfb2515487e30e322253d \
--hash=sha256:a3daabb76a78f829cafc365531c972016e4aa8d5b4bf60660ad8ecee19df7ccc \
--hash=sha256:a469274ad18dc0e4d316eefa616d1d0c2ff9da369af19fa6f3daa4f09671fd61 \
--hash=sha256:a599669fd7c47233438a56936988a2478685e74854088ef5293802123b5b2460 \
--hash=sha256:a743e5a28af5f70f9c080380a5f908d4d21d40e8f0e0c8901604d15cfa9ba751 \
--hash=sha256:a77def80806c421b4b0af06f45d65a136e7ac0bdca3c09d9e2ea4e515367c7e9 \
--hash=sha256:a7e53012d2853a07a4a79c00643832161a910674a893d296c9f1259859a289d2 \
--hash=sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0 \
--hash=sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1 \
--hash=sha256:ae15b066e5ad21366600ebec29a7ccbc86812ed267e4b28e860b8ca16a2bc474 \
--hash=sha256:aea440a510e14e818e67bfc4027880e2fb500c2ccb20ab21c7a7c8b5b4703d75 \
--hash=sha256:af6fa6817889314555aede9a919612b23739395ce767fe7fcbea9a80bf140fe5 \
--hash=sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f \
--hash=sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2 \
--hash=sha256:c247dd99d39e0338a604f8c2b3bc7061d5c2e9e2ac7ba9cc1be5a69cb6cd832f \
--hash=sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb \
--hash=sha256:c8146669223164fc87a7e3de9f81e9423c67a79d6b3447994dfb9c95da16e2d6 \
--hash=sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9 \
--hash=sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111 \
--hash=sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2 \
--hash=sha256:cb1dac1770878ade83f2ccdf7d25e494f05c9165f5246b46a621cc849341dc01 \
--hash=sha256:cdad5b9014d83ca68c25d2e9444e28e967ef16e80f6b436918c700c117a85467 \
--hash=sha256:cdbc1fc1bc0bff1cef838eafe581b55bfbffaed4ed0318b724d0b71d4d377619 \
--hash=sha256:ceb64bbc6eac5a140ca649003756940f8d6a7c444a68af170b3187623b43bebf \
--hash=sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408 \
--hash=sha256:d143fd47fad1db3d7c27a1b1d66162e855b5d50a89666af46e1679c496e8e579 \
--hash=sha256:d192f0f30804e55db0d0e0a35d83a9fead0e9a359a9ed0285dbacea60cc10a84 \
--hash=sha256:d2b35ca2c7f81d173d2fadc2f4f31e88cc5f7a39ae5b6db5513cf3383b0e0ec7 \
--hash=sha256:d342778ef319e1026af243ed0a07c97acf3bad33b9f29e7ae6a1f68fd083e90c \
--hash=sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284 \
--hash=sha256:d7702622a8b40c49bffb46e1e3ba2e81268d5c04a34f460978c6b5517a34dd52 \
--hash=sha256:db85ecf4e609a48f4b29055f1e144231b90edc90af7481aa731ba2d059226b1b \
--hash=sha256:de6551e370ef19f8de1807d0a9aa2cdfdce2e85ce88b122fe9f6b2b076837e59 \
--hash=sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752 \
--hash=sha256:e4fe605b917c70283db7dfe5ada75e04561479075761a0b3866c081d035b01c1 \
--hash=sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80 \
--hash=sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839 \
--hash=sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0 \
--hash=sha256:e93dfc1a1165e385cc8239fab7c036fb2cd8093728cbd85097b284d7b99249a2 \
--hash=sha256:efa8b278894b14d6da122a72fefcebc28445f2d3f880ac59d46c90f4c13be9a3 \
--hash=sha256:f0d8a7a6b5983c2496e364b969f0e526647a06b075d034f3297dc66f3b360c64 \
--hash=sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089 \
--hash=sha256:f296c40e23065d0d6650c4aefe7470d2a25fffda489bcc3eb66083f3ac9f6643 \
--hash=sha256:f31859074d57b4639318523d6ffdca586ace54271a73ad23ad021acd807eb14b \
--hash=sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e \
--hash=sha256:f733d788519c7e3e71f0855c96618720f5d3d60c3cb829d8bbb722dddce37985 \
--hash=sha256:fce1473f3ccc4187f75b4690cfc922628aed4d3dd013d047f95a9b3919a86596 \
--hash=sha256:fd5f17ff8f14003595ab414e45fce13d073e0762394f957182e69035c9f3d7c2 \
--hash=sha256:fdc3ff3bfccdc6b9cc7c342c03aa2400683f0cb891d46e94b64a197910dc4064
# via fonttools
cffi==1.17.1 \
--hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \
--hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \
--hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \
--hash=sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15 \
--hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \
--hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \
--hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \
--hash=sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36 \
--hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \
--hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \
--hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \
--hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \
--hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \
--hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \
--hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \
--hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \
--hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \
--hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \
--hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \
--hash=sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b \
--hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \
--hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \
--hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \
--hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \
--hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \
--hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \
--hash=sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8 \
--hash=sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1 \
--hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \
--hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \
--hash=sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67 \
--hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \
--hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \
--hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \
--hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \
--hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \
--hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \
--hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \
--hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \
--hash=sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16 \
--hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \
--hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \
--hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \
--hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \
--hash=sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c \
--hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \
--hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \
--hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \
--hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \
--hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \
--hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \
--hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \
--hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \
--hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \
--hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \
--hash=sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14 \
--hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \
--hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \
--hash=sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7 \
--hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \
--hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \
--hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \
--hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \
--hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \
--hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \
--hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \
--hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b
# via weasyprint
cfgv==3.4.0 \
--hash=sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9 \
--hash=sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560
# via pre-commit
cssselect2==0.8.0 \
--hash=sha256:46fc70ebc41ced7a32cd42d58b1884d72ade23d21e5a4eaaf022401c13f0e76e \
--hash=sha256:7674ffb954a3b46162392aee2a3a0aedb2e14ecf99fcc28644900f4e6e3e9d3a
# via weasyprint
distlib==0.4.0 \
--hash=sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 \
--hash=sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d
# via virtualenv
filelock==3.18.0 \
--hash=sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2 \
--hash=sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de
# via virtualenv
fonttools==4.59.0 \
--hash=sha256:052444a5d0151878e87e3e512a1aa1a0ab35ee4c28afde0a778e23b0ace4a7de \
--hash=sha256:169b99a2553a227f7b5fea8d9ecd673aa258617f466b2abc6091fe4512a0dcd0 \
--hash=sha256:209b75943d158f610b78320eacb5539aa9e920bee2c775445b2846c65d20e19d \
--hash=sha256:21e606b2d38fed938dde871c5736822dd6bda7a4631b92e509a1f5cd1b90c5df \
--hash=sha256:241313683afd3baacb32a6bd124d0bce7404bc5280e12e291bae1b9bba28711d \
--hash=sha256:26731739daa23b872643f0e4072d5939960237d540c35c14e6a06d47d71ca8fe \
--hash=sha256:2e7cf8044ce2598bb87e44ba1d2c6e45d7a8decf56055b92906dc53f67c76d64 \
--hash=sha256:31003b6a10f70742a63126b80863ab48175fb8272a18ca0846c0482968f0588e \
--hash=sha256:332bfe685d1ac58ca8d62b8d6c71c2e52a6c64bc218dc8f7825c9ea51385aa01 \
--hash=sha256:37c377f7cb2ab2eca8a0b319c68146d34a339792f9420fca6cd49cf28d370705 \
--hash=sha256:37e01c6ec0c98599778c2e688350d624fa4770fbd6144551bd5e032f1199171c \
--hash=sha256:401b1941ce37e78b8fd119b419b617277c65ae9417742a63282257434fd68ea2 \
--hash=sha256:4536f2695fe5c1ffb528d84a35a7d3967e5558d2af58b4775e7ab1449d65767b \
--hash=sha256:4c908a7036f0f3677f8afa577bcd973e3e20ddd2f7c42a33208d18bee95cdb6f \
--hash=sha256:51ab1ff33c19e336c02dee1e9fd1abd974a4ca3d8f7eef2a104d0816a241ce97 \
--hash=sha256:524133c1be38445c5c0575eacea42dbd44374b310b1ffc4b60ff01d881fabb96 \
--hash=sha256:57bb7e26928573ee7c6504f54c05860d867fd35e675769f3ce01b52af38d48e2 \
--hash=sha256:60f6665579e909b618282f3c14fa0b80570fbf1ee0e67678b9a9d43aa5d67a37 \
--hash=sha256:62224a9bb85b4b66d1b46d45cbe43d71cbf8f527d332b177e3b96191ffbc1e64 \
--hash=sha256:6770d7da00f358183d8fd5c4615436189e4f683bdb6affb02cad3d221d7bb757 \
--hash=sha256:6801aeddb6acb2c42eafa45bc1cb98ba236871ae6f33f31e984670b749a8e58e \
--hash=sha256:70d6b3ceaa9cc5a6ac52884f3b3d9544e8e231e95b23f138bdb78e6d4dc0eae3 \
--hash=sha256:78813b49d749e1bb4db1c57f2d4d7e6db22c253cb0a86ad819f5dc197710d4b2 \
--hash=sha256:841b2186adce48903c0fef235421ae21549020eca942c1da773ac380b056ab3c \
--hash=sha256:84fc186980231a287b28560d3123bd255d3c6b6659828c642b4cf961e2b923d0 \
--hash=sha256:885bde7d26e5b40e15c47bd5def48b38cbd50830a65f98122a8fb90962af7cd1 \
--hash=sha256:8b4309a2775e4feee7356e63b163969a215d663399cce1b3d3b65e7ec2d9680e \
--hash=sha256:8d77f92438daeaddc05682f0f3dac90c5b9829bcac75b57e8ce09cb67786073c \
--hash=sha256:902425f5afe28572d65d2bf9c33edd5265c612ff82c69e6f83ea13eafc0dcbea \
--hash=sha256:9bcc1e77fbd1609198966ded6b2a9897bd6c6bcbd2287a2fc7d75f1a254179c5 \
--hash=sha256:a408c3c51358c89b29cfa5317cf11518b7ce5de1717abb55c5ae2d2921027de6 \
--hash=sha256:a9bf8adc9e1f3012edc8f09b08336272aec0c55bc677422273e21280db748f7c \
--hash=sha256:b818db35879d2edf7f46c7e729c700a0bce03b61b9412f5a7118406687cb151d \
--hash=sha256:b8974b2a266b54c96709bd5e239979cddfd2dbceed331aa567ea1d7c4a2202db \
--hash=sha256:be392ec3529e2f57faa28709d60723a763904f71a2b63aabe14fee6648fe3b14 \
--hash=sha256:d3972b13148c1d1fbc092b27678a33b3080d1ac0ca305742b0119b75f9e87e38 \
--hash=sha256:d40dcf533ca481355aa7b682e9e079f766f35715defa4929aeb5597f9604272e \
--hash=sha256:e93df708c69a193fc7987192f94df250f83f3851fda49413f02ba5dded639482 \
--hash=sha256:efd7e6660674e234e29937bc1481dceb7e0336bfae75b856b4fb272b5093c5d4 \
--hash=sha256:f9b3a78f69dcbd803cf2fb3f972779875b244c1115481dfbdd567b2c22b31f6b \
--hash=sha256:fa39475eaccb98f9199eccfda4298abaf35ae0caec676ffc25b3a5e224044464 \
--hash=sha256:fbce6dae41b692a5973d0f2158f782b9ad05babc2c2019a970a1094a23909b1b
# via weasyprint
identify==2.6.13 \
--hash=sha256:60381139b3ae39447482ecc406944190f690d4a2997f2584062089848361b33b \
--hash=sha256:da8d6c828e773620e13bfa86ea601c5a5310ba4bcd65edf378198b56a1f9fb32
# via pre-commit
nodeenv==1.9.1 \
--hash=sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f \
--hash=sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9
# via pre-commit
numpy==2.2.6 \
--hash=sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff \
--hash=sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47 \
--hash=sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84 \
--hash=sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d \
--hash=sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6 \
--hash=sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f \
--hash=sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b \
--hash=sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49 \
--hash=sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163 \
--hash=sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571 \
--hash=sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42 \
--hash=sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff \
--hash=sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491 \
--hash=sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4 \
--hash=sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566 \
--hash=sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf \
--hash=sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40 \
--hash=sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd \
--hash=sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06 \
--hash=sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282 \
--hash=sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680 \
--hash=sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db \
--hash=sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3 \
--hash=sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90 \
--hash=sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1 \
--hash=sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289 \
--hash=sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab \
--hash=sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c \
--hash=sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d \
--hash=sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb \
--hash=sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d \
--hash=sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a \
--hash=sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf \
--hash=sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1 \
--hash=sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2 \
--hash=sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a \
--hash=sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543 \
--hash=sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00 \
--hash=sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c \
--hash=sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f \
--hash=sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd \
--hash=sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868 \
--hash=sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303 \
--hash=sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83 \
--hash=sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3 \
--hash=sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d \
--hash=sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87 \
--hash=sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa \
--hash=sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f \
--hash=sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae \
--hash=sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda \
--hash=sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915 \
--hash=sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249 \
--hash=sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de \
--hash=sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8
# via opencv-python-headless
opencv-python-headless==4.12.0.88 \
--hash=sha256:1e58d664809b3350c1123484dd441e1667cd7bed3086db1b9ea1b6f6cb20b50e \
--hash=sha256:236c8df54a90f4d02076e6f9c1cc763d794542e886c576a6fee46ec8ff75a7a9 \
--hash=sha256:365bb2e486b50feffc2d07a405b953a8f3e8eaa63865bc650034e5c71e7a5154 \
--hash=sha256:86b413bdd6c6bf497832e346cd5371995de148e579b9774f8eba686dee3f5528 \
--hash=sha256:aeb4b13ecb8b4a0beb2668ea07928160ea7c2cd2d9b5ef571bbee6bafe9cc8d0 \
--hash=sha256:cfdc017ddf2e59b6c2f53bc12d74b6b0be7ded4ec59083ea70763921af2b6c09 \
--hash=sha256:fde2cf5c51e4def5f2132d78e0c08f9c14783cd67356922182c6845b9af87dbd
# via -r .github\scripts\requirements_dev.in
pdf2image==1.17.0 \
--hash=sha256:eaa959bc116b420dd7ec415fcae49b98100dda3dd18cd2fdfa86d09f112f6d57 \
--hash=sha256:ecdd58d7afb810dffe21ef2b1bbc057ef434dabbac6c33778a38a3f7744a27e2
# via -r .github\scripts\requirements_dev.in
pillow==11.3.0 \
--hash=sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2 \
--hash=sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214 \
--hash=sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e \
--hash=sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59 \
--hash=sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50 \
--hash=sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632 \
--hash=sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06 \
--hash=sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a \
--hash=sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51 \
--hash=sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced \
--hash=sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f \
--hash=sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12 \
--hash=sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8 \
--hash=sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6 \
--hash=sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580 \
--hash=sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f \
--hash=sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac \
--hash=sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860 \
--hash=sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd \
--hash=sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722 \
--hash=sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8 \
--hash=sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4 \
--hash=sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673 \
--hash=sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788 \
--hash=sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542 \
--hash=sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e \
--hash=sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd \
--hash=sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8 \
--hash=sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523 \
--hash=sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967 \
--hash=sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809 \
--hash=sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477 \
--hash=sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027 \
--hash=sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae \
--hash=sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b \
--hash=sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c \
--hash=sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f \
--hash=sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e \
--hash=sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b \
--hash=sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7 \
--hash=sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27 \
--hash=sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361 \
--hash=sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae \
--hash=sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d \
--hash=sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc \
--hash=sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58 \
--hash=sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad \
--hash=sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6 \
--hash=sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024 \
--hash=sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978 \
--hash=sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb \
--hash=sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d \
--hash=sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0 \
--hash=sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9 \
--hash=sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f \
--hash=sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874 \
--hash=sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa \
--hash=sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081 \
--hash=sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149 \
--hash=sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6 \
--hash=sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d \
--hash=sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd \
--hash=sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f \
--hash=sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c \
--hash=sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31 \
--hash=sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e \
--hash=sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db \
--hash=sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6 \
--hash=sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f \
--hash=sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494 \
--hash=sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69 \
--hash=sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94 \
--hash=sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77 \
--hash=sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d \
--hash=sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7 \
--hash=sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a \
--hash=sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438 \
--hash=sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288 \
--hash=sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b \
--hash=sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635 \
--hash=sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3 \
--hash=sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d \
--hash=sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe \
--hash=sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0 \
--hash=sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe \
--hash=sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a \
--hash=sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805 \
--hash=sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8 \
--hash=sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36 \
--hash=sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a \
--hash=sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b \
--hash=sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e \
--hash=sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25 \
--hash=sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12 \
--hash=sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada \
--hash=sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c \
--hash=sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71 \
--hash=sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d \
--hash=sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c \
--hash=sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6 \
--hash=sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1 \
--hash=sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50 \
--hash=sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653 \
--hash=sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c \
--hash=sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4 \
--hash=sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3
# via
# -r .github\scripts\requirements_dev.in
# pdf2image
# weasyprint
platformdirs==4.3.8 \
--hash=sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc \
--hash=sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4
# via virtualenv
pre-commit==4.3.0 \
--hash=sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8 \
--hash=sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16
# via -r .github\scripts\requirements_dev.in
pycparser==2.22 \
--hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
--hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
# via cffi
pydyf==0.11.0 \
--hash=sha256:0aaf9e2ebbe786ec7a78ec3fbffa4cdcecde53fd6f563221d53c6bc1328848a3 \
--hash=sha256:394dddf619cca9d0c55715e3c55ea121a9bf9cbc780cdc1201a2427917b86b64
# via weasyprint
pyphen==0.17.2 \
--hash=sha256:3a07fb017cb2341e1d9ff31b8634efb1ae4dc4b130468c7c39dd3d32e7c3affd \
--hash=sha256:f60647a9c9b30ec6c59910097af82bc5dd2d36576b918e44148d8b07ef3b4aa3
# via weasyprint
pyyaml==6.0.2 \
--hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \
--hash=sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48 \
--hash=sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086 \
--hash=sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e \
--hash=sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133 \
--hash=sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5 \
--hash=sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484 \
--hash=sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee \
--hash=sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5 \
--hash=sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68 \
--hash=sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a \
--hash=sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf \
--hash=sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99 \
--hash=sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8 \
--hash=sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85 \
--hash=sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19 \
--hash=sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc \
--hash=sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a \
--hash=sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1 \
--hash=sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317 \
--hash=sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c \
--hash=sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631 \
--hash=sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d \
--hash=sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652 \
--hash=sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 \
--hash=sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e \
--hash=sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b \
--hash=sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8 \
--hash=sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476 \
--hash=sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706 \
--hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563 \
--hash=sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237 \
--hash=sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b \
--hash=sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083 \
--hash=sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180 \
--hash=sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425 \
--hash=sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e \
--hash=sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f \
--hash=sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725 \
--hash=sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183 \
--hash=sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab \
--hash=sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774 \
--hash=sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725 \
--hash=sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e \
--hash=sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5 \
--hash=sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d \
--hash=sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290 \
--hash=sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44 \
--hash=sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed \
--hash=sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4 \
--hash=sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba \
--hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \
--hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4
# via pre-commit
tinycss2==1.4.0 \
--hash=sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7 \
--hash=sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289
# via
# cssselect2
# weasyprint
tinyhtml5==2.0.0 \
--hash=sha256:086f998833da24c300c414d9fe81d9b368fd04cb9d2596a008421cbc705fcfcc \
--hash=sha256:13683277c5b176d070f82d099d977194b7a1e26815b016114f581a74bbfbf47e
# via weasyprint
unoserver==3.3.2 \
--hash=sha256:1eeb7467cf6b56b8eff3b576e2d1b2b2ff4e0eb2052e995ac80a1456de300639 \
--hash=sha256:87e144f903ee21951b2e06a97549450c13ed7eca5bcebad942d3352d4e882616
# via -r .github\scripts\requirements_dev.in
virtualenv==20.33.1 \
--hash=sha256:07c19bc66c11acab6a5958b815cbcee30891cd1c2ccf53785a28651a0d8d8a67 \
--hash=sha256:1b44478d9e261b3fb8baa5e74a0ca3bc0e05f21aa36167bf9cbf850e542765b8
# via pre-commit
weasyprint==66.0 \
--hash=sha256:82b0783b726fcd318e2c977dcdddca76515b30044bc7a830cc4fbe717582a6d0 \
--hash=sha256:da71dc87dc129ac9cffdc65e5477e90365ab9dbae45c744014ec1d06303dde40
# via -r .github\scripts\requirements_dev.in
webencodings==0.5.1 \
--hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \
--hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923
# via
# cssselect2
# tinycss2
# tinyhtml5
zopfli==0.2.3.post1 \
--hash=sha256:0aa5f90d6298bda02a95bc8dc8c3c19004d5a4e44bda00b67ca7431d857b4b54 \
--hash=sha256:0cc20b02a9531559945324c38302fd4ba763311632d0ec8a1a0aa9c10ea363e6 \
--hash=sha256:1d8cc06605519e82b16df090e17cb3990d1158861b2872c3117f1168777b81e4 \
--hash=sha256:1f990634fd5c5c8ced8edddd8bd45fab565123b4194d6841e01811292650acae \
--hash=sha256:2345e713260a350bea0b01a816a469ea356bc2d63d009a0d777691ecbbcf7493 \
--hash=sha256:2768c877f76c8a0e7519b1c86c93757f3c01492ddde55751e9988afb7eff64e1 \
--hash=sha256:29ea74e72ffa6e291b8c6f2504ce6c146b4fe990c724c1450eb8e4c27fd31431 \
--hash=sha256:34a99592f3d9eb6f737616b5bd74b48a589fdb3cb59a01a50d636ea81d6af272 \
--hash=sha256:3654bfc927bc478b1c3f3ff5056ed7b20a1a37fa108ca503256d0a699c03bbb1 \
--hash=sha256:3657e416ffb8f31d9d3424af12122bb251befae109f2e271d87d825c92fc5b7b \
--hash=sha256:37d011e92f7b9622742c905fdbed9920a1d0361df84142807ea2a528419dea7f \
--hash=sha256:3827170de28faf144992d3d4dcf8f3998fe3c8a6a6f4a08f1d42c2ec6119d2bb \
--hash=sha256:39e576f93576c5c223b41d9c780bbb91fd6db4babf3223d2a4fe7bf568e2b5a8 \
--hash=sha256:3a89277ed5f8c0fb2d0b46d669aa0633123aa7381f1f6118c12f15e0fb48f8ca \
--hash=sha256:3c163911f8bad94b3e1db0a572e7c28ba681a0c91d0002ea1e4fa9264c21ef17 \
--hash=sha256:3f0197b6aa6eb3086ae9e66d6dd86c4d502b6c68b0ec490496348ae8c05ecaef \
--hash=sha256:48dba9251060289101343110ab47c0756f66f809bb4d1ddbb6d5c7e7752115c5 \
--hash=sha256:4915a41375bdee4db749ecd07d985a0486eb688a6619f713b7bf6fbfd145e960 \
--hash=sha256:4c1226a7e2c7105ac31503a9bb97454743f55d88164d6d46bc138051b77f609b \
--hash=sha256:4e50ffac74842c1c1018b9b73875a0d0a877c066ab06bf7cccbaa84af97e754f \
--hash=sha256:518f1f4ed35dd69ce06b552f84e6d081f07c552b4c661c5312d950a0b764a58a \
--hash=sha256:5aad740b4d4fcbaaae4887823925166ffd062db3b248b3f432198fc287381d1a \
--hash=sha256:5f272186e03ad55e7af09ab78055535c201b1a0bcc2944edb1768298d9c483a4 \
--hash=sha256:5fcfc0dc2761e4fcc15ad5d273b4d58c2e8e059d3214a7390d4d3c8e2aee644e \
--hash=sha256:60db20f06c3d4c5934b16cfa62a2cc5c3f0686bffe0071ed7804d3c31ab1a04e \
--hash=sha256:615a8ac9dda265e9cc38b2a76c3142e4a9f30fea4a79c85f670850783bc6feb4 \
--hash=sha256:6482db9876c68faac2d20a96b566ffbf65ddaadd97b222e4e73641f4f8722fc4 \
--hash=sha256:6617fb10f9e4393b331941861d73afb119cd847e88e4974bdbe8068ceef3f73f \
--hash=sha256:676919fba7311125244eb0c4393679ac5fe856e5864a15d122bd815205369fa0 \
--hash=sha256:6c2d2bc8129707e34c51f9352c4636ca313b52350bbb7e04637c46c1818a2a70 \
--hash=sha256:71390dbd3fbf6ebea9a5d85ffed8c26ee1453ee09248e9b88486e30e0397b775 \
--hash=sha256:716cdbfc57bfd3d3e31a58e6246e8190e6849b7dbb7c4ce39ef8bbf0edb8f6d5 \
--hash=sha256:75a26a2307b10745a83b660c404416e984ee6fca515ec7f0765f69af3ce08072 \
--hash=sha256:7be5cc6732eb7b4df17305d8a7b293223f934a31783a874a01164703bc1be6cd \
--hash=sha256:7cce242b5df12b2b172489daf19c32e5577dd2fac659eb4b17f6a6efb446fd5c \
--hash=sha256:81c341d9bb87a6dbbb0d45d6e272aca80c7c97b4b210f9b6e233bf8b87242f29 \
--hash=sha256:89899641d4de97dbad8e0cde690040d078b6aea04066dacaab98e0b5a23573f2 \
--hash=sha256:8d5ab297d660b75c159190ce6d73035502310e40fd35170aed7d1a1aea7ddd65 \
--hash=sha256:8fbe5bcf10d01aab3513550f284c09fef32f342b36f56bfae2120a9c4d12c130 \
--hash=sha256:91a2327a4d7e77471fa4fbb26991c6de4a738c6fc6a33e09bb25f56a870a4b7b \
--hash=sha256:95a260cafd56b8fffa679918937401c80bb38e1681c448b988022e4c3610965d \
--hash=sha256:96484dc0f48be1c5d7ae9f38ed1ce41e3675fd506b27c11a6607f14b49101e99 \
--hash=sha256:9a6aec38a989bad7ddd1ef53f1265699e49e294d08231b5313d61293f3cd6237 \
--hash=sha256:9ba214f4f45bec195ee8559651154d3ac2932470b9d91c5715fc29c013349f8c \
--hash=sha256:9f4a7ec2770e6af05f5a02733fd3900f30a9cd58e5d6d3727e14c5bcd6e7d587 \
--hash=sha256:a1cf720896d2ce998bc8e051d4b4ce0d8bec007aab6243102e8e1d22a0b2fb3f \
--hash=sha256:a241a68581d34d67b40c425cce3d1fd211c092f99d9250947824ccba9f491949 \
--hash=sha256:a53b18797cdef27e019db595d66c4b077325afe2fd62145953275f53d84ce40c \
--hash=sha256:a82fc2dbebe6eb908b9c665e71496f8525c1bc4d2e3a7a7722ef2b128b6227c8 \
--hash=sha256:a86eb88e06bd87e1fff31dac878965c26b0c26db59ddcf78bb0379a954b120de \
--hash=sha256:aa588b21044f8a74e423d8c8a4c7fc9988501878aacced793467010039c50734 \
--hash=sha256:b05296e8bc88c92e2b21e0a9bae4740c1551ee613c1d93a51fd28a7a0b2b6fbb \
--hash=sha256:b0ec13f352ea5ae0fc91f98a48540512eed0767d0ec4f7f3cb92d92797983d18 \
--hash=sha256:b3df42f52502438ee973042cc551877d24619fa1cd38ef7b7e9ac74200daca8b \
--hash=sha256:b78008a69300d929ca2efeffec951b64a312e9a811e265ea4a907ab546d79fa6 \
--hash=sha256:b9026a21b6d41eb0e2e63f5bc1242c3fcc43ecb770963cda99a4307863dac12e \
--hash=sha256:bbe429fc50686bb2a2608a30843e36fbaa123462a5284f136c7d9e0145220bfd \
--hash=sha256:bfa1eb759e07d8b7aa7a310a2bc535e127ee70addf90dc8d4b946b593c3e51a8 \
--hash=sha256:c1e0ed5d84ffa2d677cc9582fc01e61dab2e7ef8b8996e055f0a76167b1b94df \
--hash=sha256:c4278d1873ce6e803e5d4f8d702fd3026bd67fca744aa98881324d1157ddf748 \
--hash=sha256:cac2b37ab21c2b36a10b685b1893ebd6b0f83ae26004838ac817680881576567 \
--hash=sha256:cbe6df25807227519debd1a57ab236f5f6bad441500e85b13903e51f93a43214 \
--hash=sha256:cd2c002f160502608dcc822ed2441a0f4509c52e86fcfd1a09e937278ed1ca14 \
--hash=sha256:e0137dd64a493ba6a4be37405cfd6febe650a98cc1e9dca8f6b8c63b1db11b41 \
--hash=sha256:e63d558847166543c2c9789e6f985400a520b7eacc4b99181668b2c3aeadd352 \
--hash=sha256:eb45a34f23da4f8bc712b6376ca5396914b0b7c09adbb001dad964eb7f3132f8 \
--hash=sha256:ecb7572df5372abce8073df078207d9d1749f20b8b136089916a4a0868d56051 \
--hash=sha256:f12000a6accdd4bf0a3fa6eaa1b1c7a7bc80af0a2edf3f89d770d3dcce1d0e22 \
--hash=sha256:f7d69c1a7168ad0e9cb864e8663acb232986a0c9c9cb9801f56bf6214f53a54d \
--hash=sha256:f815fcc2b2a457977724bad97fb4854022980f51ce7b136925e336b530545ae1 \
--hash=sha256:fc39f5c27f962ec8660d8d20c24762431131b5d8c672b44b0a54cf2b5bcde9b9
# via fonttools
# The following packages are considered to be unsafe in a requirements file:
pip==25.2 \
--hash=sha256:578283f006390f85bb6282dffb876454593d637f5d1be494b5202ce4877e71f2 \
--hash=sha256:6d67a2b4e7f14d8b31b8b52648866fa717f45a1eb70e83002f4331d07e953717
# via -r .github\scripts\requirements_dev.in
setuptools==80.9.0 \
--hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922 \
--hash=sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c
# via -r .github\scripts\requirements_dev.in
+16 -12
View File
@@ -8,17 +8,17 @@ cfgv==3.4.0 \
--hash=sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9 \
--hash=sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560
# via pre-commit
distlib==0.3.9 \
--hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \
--hash=sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403
distlib==0.4.0 \
--hash=sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 \
--hash=sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d
# via virtualenv
filelock==3.18.0 \
--hash=sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2 \
--hash=sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de
# via virtualenv
identify==2.6.12 \
--hash=sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2 \
--hash=sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6
identify==2.6.13 \
--hash=sha256:60381139b3ae39447482ecc406944190f690d4a2997f2584062089848361b33b \
--hash=sha256:da8d6c828e773620e13bfa86ea601c5a5310ba4bcd65edf378198b56a1f9fb32
# via pre-commit
nodeenv==1.9.1 \
--hash=sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f \
@@ -28,9 +28,9 @@ platformdirs==4.3.8 \
--hash=sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc \
--hash=sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4
# via virtualenv
pre-commit==4.2.0 \
--hash=sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146 \
--hash=sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd
pre-commit==4.3.0 \
--hash=sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8 \
--hash=sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16
# via -r .github\scripts\requirements_pre_commit.in
pyyaml==6.0.2 \
--hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \
@@ -87,7 +87,11 @@ pyyaml==6.0.2 \
--hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \
--hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4
# via pre-commit
virtualenv==20.31.2 \
--hash=sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11 \
--hash=sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af
typing-extensions==4.14.1 \
--hash=sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36 \
--hash=sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76
# via virtualenv
virtualenv==20.34.0 \
--hash=sha256:341f5afa7eee943e4984a9207c025feedd768baff6753cd660c857ceb3e36026 \
--hash=sha256:44815b2c9dee7ed86e387b842a84f20b93f7f417f95886ca1996a72a4138eb1a
# via pre-commit
-505
View File
@@ -1,505 +0,0 @@
name: Auto PR V2 Deployment
on:
pull_request:
types: [opened, synchronize, reopened, closed]
permissions:
contents: read
issues: write
pull-requests: write
jobs:
check-pr:
if: github.event.action != 'closed'
runs-on: ubuntu-latest
outputs:
should_deploy: ${{ steps.check-conditions.outputs.should_deploy }}
pr_number: ${{ github.event.number }}
pr_repository: ${{ steps.get-pr-info.outputs.repository }}
pr_ref: ${{ steps.get-pr-info.outputs.ref }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- name: Check deployment conditions
id: check-conditions
env:
PR_TITLE: ${{ github.event.pull_request.title }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
PR_BRANCH: ${{ github.event.pull_request.head.ref }}
run: |
echo "PR Title: $PR_TITLE"
echo "PR Author: $PR_AUTHOR"
echo "PR Branch: $PR_BRANCH"
echo "PR Base Branch: ${{ github.event.pull_request.base.ref }}"
# Define authorized users
authorized_users=(
"Frooodle"
"sf298"
"Ludy87"
"LaserKaspar"
"sbplat"
"reecebrowne"
"DarioGii"
"ConnorYoh"
"EthanHealy01"
"jbrunton96"
)
# Check if author is in the authorized list
is_authorized=false
for user in "${authorized_users[@]}"; do
if [[ "$PR_AUTHOR" == "$user" ]]; then
is_authorized=true
break
fi
done
# If PR is targeting V2 and user is authorized, deploy unconditionally
PR_BASE_BRANCH="${{ github.event.pull_request.base.ref }}"
if [[ "$PR_BASE_BRANCH" == "V2" && "$is_authorized" == "true" ]]; then
echo "✅ Deployment forced: PR targets V2 and author is authorized."
echo "should_deploy=true" >> $GITHUB_OUTPUT
exit 0
fi
# Otherwise, continue with original keyword checks
has_v2_keyword=false
if [[ "$PR_TITLE" =~ [Vv]2 ]] || [[ "$PR_TITLE" =~ [Vv]ersion.?2 ]] || [[ "$PR_TITLE" =~ [Vv]ersion.?[Tt]wo ]]; then
has_v2_keyword=true
fi
has_branch_keyword=false
if [[ "$PR_BRANCH" =~ [Vv]2 ]] || [[ "$PR_BRANCH" =~ [Rr]eact ]]; then
has_branch_keyword=true
fi
if [[ "$is_authorized" == "true" && ( "$has_v2_keyword" == "true" || "$has_branch_keyword" == "true" ) ]]; then
echo "✅ Deployment conditions met"
echo "should_deploy=true" >> $GITHUB_OUTPUT
else
echo "❌ Deployment conditions not met"
echo " - Authorized user: $is_authorized"
echo " - Has V2 keyword in title: $has_v2_keyword"
echo " - Has V2/React keyword in branch: $has_branch_keyword"
echo "should_deploy=false" >> $GITHUB_OUTPUT
fi
- name: Get PR repository and ref
id: get-pr-info
if: steps.check-conditions.outputs.should_deploy == 'true'
run: |
# For forks, use the full repository name, for internal PRs use the current repo
if [[ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]]; then
repository="${{ github.event.pull_request.head.repo.full_name }}"
else
repository="${{ github.repository }}"
fi
echo "repository=$repository" >> $GITHUB_OUTPUT
echo "ref=${{ github.event.pull_request.head.ref }}" >> $GITHUB_OUTPUT
deploy-v2-pr:
needs: check-pr
runs-on: ubuntu-latest
if: needs.check-pr.outputs.should_deploy == 'true'
# Concurrency control - only one deployment per PR at a time
concurrency:
group: v2-deploy-pr-${{ needs.check-pr.outputs.pr_number }}
cancel-in-progress: true
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- name: Checkout main repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
repository: ${{ github.repository }}
ref: main
- name: Setup GitHub App Bot
if: github.actor != 'dependabot[bot]'
id: setup-bot
uses: ./.github/actions/setup-bot
continue-on-error: true
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Add deployment started comment
id: deployment-started
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ steps.setup-bot.outputs.token }}
script: |
const { owner, repo } = context.repo;
const prNumber = ${{ needs.check-pr.outputs.pr_number }};
// Delete previous V2 deployment comments to avoid clutter
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number: prNumber,
per_page: 100
});
const v2Comments = comments.filter(comment =>
comment.body.includes('🚀 **Auto-deploying V2 version**') ||
comment.body.includes('## 🚀 V2 Auto-Deployment Complete!') ||
comment.body.includes('❌ **V2 Auto-deployment failed**')
);
for (const comment of v2Comments) {
console.log(`Deleting old V2 comment: ${comment.id}`);
await github.rest.issues.deleteComment({
owner,
repo,
comment_id: comment.id
});
}
// Create new deployment started comment
const { data: newComment } = await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: `🚀 **Auto-deploying V2 version** for PR #${prNumber}...\n\n_This is an automated deployment triggered by V2/version2 keywords in the PR title or V2/React keywords in the branch name._\n\n⚠️ **Note:** If new commits are pushed during deployment, this build will be cancelled and replaced with the latest version.`
});
return newComment.id;
- name: Checkout PR
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
repository: ${{ needs.check-pr.outputs.pr_repository }}
ref: ${{ needs.check-pr.outputs.pr_ref }}
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0 # Fetch full history for commit hash detection
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Get version number
id: versionNumber
run: |
VERSION=$(grep "^version =" build.gradle | awk -F'"' '{print $2}')
echo "versionNumber=$VERSION" >> $GITHUB_OUTPUT
- name: Login to Docker Hub
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_API }}
- name: Get commit hashes for frontend and backend
id: commit-hashes
run: |
# Get last commit that touched the frontend folder, docker/frontend, or docker/compose
FRONTEND_HASH=$(git log -1 --format="%H" -- frontend/ docker/frontend/ docker/compose/ 2>/dev/null || echo "")
if [ -z "$FRONTEND_HASH" ]; then
FRONTEND_HASH="no-frontend-changes"
fi
# Get last commit that touched backend code, docker/backend, or docker/compose
BACKEND_HASH=$(git log -1 --format="%H" -- app/ docker/backend/ docker/compose/ 2>/dev/null || echo "")
if [ -z "$BACKEND_HASH" ]; then
BACKEND_HASH="no-backend-changes"
fi
echo "Frontend hash: $FRONTEND_HASH"
echo "Backend hash: $BACKEND_HASH"
echo "frontend_hash=$FRONTEND_HASH" >> $GITHUB_OUTPUT
echo "backend_hash=$BACKEND_HASH" >> $GITHUB_OUTPUT
# Short hashes for tags
if [ "$FRONTEND_HASH" = "no-frontend-changes" ]; then
echo "frontend_short=no-frontend" >> $GITHUB_OUTPUT
else
echo "frontend_short=${FRONTEND_HASH:0:8}" >> $GITHUB_OUTPUT
fi
if [ "$BACKEND_HASH" = "no-backend-changes" ]; then
echo "backend_short=no-backend" >> $GITHUB_OUTPUT
else
echo "backend_short=${BACKEND_HASH:0:8}" >> $GITHUB_OUTPUT
fi
- name: Check if frontend image exists
id: check-frontend
run: |
if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} >/dev/null 2>&1; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "Frontend image already exists, skipping build"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "Frontend image needs to be built"
fi
- name: Check if backend image exists
id: check-backend
run: |
if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} >/dev/null 2>&1; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "Backend image already exists, skipping build"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "Backend image needs to be built"
fi
- name: Build and push V2 frontend image
if: steps.check-frontend.outputs.exists == 'false'
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: .
file: ./docker/frontend/Dockerfile
push: true
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }}
build-args: VERSION_TAG=v2-alpha
platforms: linux/amd64
- name: Build and push V2 backend image
if: steps.check-backend.outputs.exists == 'false'
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: .
file: ./docker/backend/Dockerfile
push: true
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }}
build-args: VERSION_TAG=v2-alpha
platforms: linux/amd64
- name: Set up SSH
run: |
mkdir -p ~/.ssh/
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
sudo chmod 600 ../private.key
- name: Deploy V2 to VPS
id: deploy
run: |
# Use same port strategy as regular PRs - just the PR number
V2_PORT=${{ needs.check-pr.outputs.pr_number }}
BACKEND_PORT=$((V2_PORT + 10000)) # Backend on higher port to avoid conflicts
# Create docker-compose for V2 with separate frontend and backend
cat > docker-compose.yml << EOF
version: '3.3'
services:
stirling-pdf-v2-backend:
container_name: stirling-pdf-v2-backend-pr-${{ needs.check-pr.outputs.pr_number }}
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }}
ports:
- "${BACKEND_PORT}:8080" # Backend API port
volumes:
- /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/data:/usr/share/tessdata:rw
- /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/config:/configs:rw
- /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/logs:/logs:rw
environment:
DISABLE_ADDITIONAL_FEATURES: "true"
SECURITY_ENABLELOGIN: "false"
SYSTEM_DEFAULTLOCALE: en-GB
UI_APPNAME: "Stirling-PDF V2 PR#${{ needs.check-pr.outputs.pr_number }}"
UI_HOMEDESCRIPTION: "V2 PR#${{ needs.check-pr.outputs.pr_number }} - Frontend/Backend Split Architecture"
UI_APPNAMENAVBAR: "V2 PR#${{ needs.check-pr.outputs.pr_number }}"
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "false"
SWAGGER_SERVER_URL: "https://${V2_PORT}.ssl.stirlingpdf.cloud"
baseUrl: "https://${V2_PORT}.ssl.stirlingpdf.cloud"
restart: on-failure:5
stirling-pdf-v2-frontend:
container_name: stirling-pdf-v2-frontend-pr-${{ needs.check-pr.outputs.pr_number }}
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }}
ports:
- "${V2_PORT}:80" # Frontend port (same as regular PRs)
environment:
VITE_API_BASE_URL: "http://${{ secrets.VPS_HOST }}:${BACKEND_PORT}"
depends_on:
- stirling-pdf-v2-backend
restart: on-failure:5
EOF
# Deploy to VPS
scp -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null docker-compose.yml ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }}:/tmp/docker-compose-v2.yml
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << ENDSSH
# Create V2 PR-specific directories
mkdir -p /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/{data,config,logs}
# Move docker-compose file to correct location
mv /tmp/docker-compose-v2.yml /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/docker-compose.yml
# Stop any existing container and clean up
cd /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}
docker-compose down --remove-orphans 2>/dev/null || true
# Start the new container
docker-compose pull
docker-compose up -d
# Clean up unused Docker resources to save space
docker system prune -af --volumes || true
# Clean up old backend/frontend images (older than 2 weeks)
docker image prune -af --filter "until=336h" --filter "label!=keep=true" || true
ENDSSH
# Set port for output
echo "v2_port=${V2_PORT}" >> $GITHUB_OUTPUT
- name: Post V2 deployment URL to PR
if: success()
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ steps.setup-bot.outputs.token }}
script: |
const { owner, repo } = context.repo;
const prNumber = ${{ needs.check-pr.outputs.pr_number }};
const v2Port = ${{ steps.deploy.outputs.v2_port }};
// Delete the "deploying..." comment since we're posting the final result
const deploymentStartedId = ${{ steps.deployment-started.outputs.result }};
if (deploymentStartedId) {
console.log(`Deleting deployment started comment: ${deploymentStartedId}`);
try {
await github.rest.issues.deleteComment({
owner,
repo,
comment_id: deploymentStartedId
});
} catch (error) {
console.log(`Could not delete deployment started comment: ${error.message}`);
}
}
const deploymentUrl = `http://${{ secrets.VPS_HOST }}:${v2Port}`;
const httpsUrl = `https://${v2Port}.ssl.stirlingpdf.cloud`;
const commentBody = `## 🚀 V2 Auto-Deployment Complete!\n\n` +
`Your V2 PR with the new frontend/backend split architecture has been deployed!\n\n` +
`🔗 **Direct Test URL (non-SSL)** [${deploymentUrl}](${deploymentUrl})\n\n` +
`🔐 **Secure HTTPS URL**: [${httpsUrl}](${httpsUrl})\n\n` +
`_This deployment will be automatically cleaned up when the PR is closed._\n\n` +
`🔄 **Auto-deployed** because PR title or branch name contains V2/version2/React keywords.`;
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: commentBody
});
cleanup-v2-deployment:
if: github.event.action == 'closed'
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup GitHub App Bot
if: github.actor != 'dependabot[bot]'
id: setup-bot
uses: ./.github/actions/setup-bot
continue-on-error: true
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Clean up V2 deployment comments
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ steps.setup-bot.outputs.token }}
script: |
const { owner, repo } = context.repo;
const prNumber = ${{ github.event.pull_request.number }};
// Find and delete V2 deployment comments
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number: prNumber
});
const v2Comments = comments.filter(c =>
c.body?.includes("## 🚀 V2 Auto-Deployment Complete!") &&
c.user?.type === "Bot"
);
for (const comment of v2Comments) {
await github.rest.issues.deleteComment({
owner,
repo,
comment_id: comment.id
});
console.log(`Deleted V2 deployment comment (ID: ${comment.id})`);
}
- name: Set up SSH
run: |
mkdir -p ~/.ssh/
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
sudo chmod 600 ../private.key
- name: Cleanup V2 deployment
run: |
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
if [ -d "/stirling/V2-PR-${{ github.event.pull_request.number }}" ]; then
echo "Found V2 PR directory, proceeding with cleanup..."
# Stop and remove V2 containers
cd /stirling/V2-PR-${{ github.event.pull_request.number }}
docker-compose down || true
# Go back to root before removal
cd /
# Remove V2 PR-specific directories
rm -rf /stirling/V2-PR-${{ github.event.pull_request.number }}
# Clean up V2 containers by name (in case compose cleanup missed them)
docker rm -f stirling-pdf-v2-frontend-pr-${{ github.event.pull_request.number }} || true
docker rm -f stirling-pdf-v2-backend-pr-${{ github.event.pull_request.number }} || true
echo "V2 cleanup completed"
else
echo "V2 PR directory not found, nothing to clean up"
fi
# Clean up old unused images (older than 2 weeks) but keep recent ones for reuse
docker image prune -af --filter "until=336h" --filter "label!=keep=true" || true
# Note: We don't remove the commit-based images since they can be reused across PRs
# Only remove PR-specific containers and directories
ENDSSH
- name: Cleanup temporary files
if: always()
run: |
rm -f ../private.key
continue-on-error: true
@@ -29,13 +29,10 @@ jobs:
github.event.comment.user.login == 'reecebrowne' ||
github.event.comment.user.login == 'DarioGii' ||
github.event.comment.user.login == 'EthanHealy01' ||
github.event.comment.user.login == 'jbrunton96' ||
github.event.comment.user.login == 'ConnorYoh'
)
outputs:
pr_number: ${{ steps.get-pr.outputs.pr_number }}
pr_repository: ${{ steps.get-pr-info.outputs.repository }}
pr_ref: ${{ steps.get-pr-info.outputs.ref }}
comment_id: ${{ github.event.comment.id }}
disable_security: ${{ steps.check-security-flag.outputs.disable_security }}
enable_pro: ${{ steps.check-pro-flag.outputs.enable_pro }}
@@ -47,7 +44,7 @@ jobs:
egress-policy: audit
- name: Checkout PR
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup GitHub App Bot
if: github.actor != 'dependabot[bot]'
@@ -67,29 +64,6 @@ jobs:
console.log(`PR Number: ${prNumber}`);
core.setOutput('pr_number', prNumber);
- name: Get PR repository and ref
id: get-pr-info
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const { owner, repo } = context.repo;
const prNumber = context.payload.issue.number;
const { data: pr } = await github.rest.pulls.get({
owner,
repo,
pull_number: prNumber,
});
// For forks, use the full repository name, for internal PRs use the current repo
const repository = pr.head.repo.fork ? pr.head.repo.full_name : `${owner}/${repo}`;
console.log(`PR Repository: ${repository}`);
console.log(`PR Branch: ${pr.head.ref}`);
core.setOutput('repository', repository);
core.setOutput('ref', pr.head.ref);
- name: Check for security/login flag
id: check-security-flag
env:
@@ -158,7 +132,7 @@ jobs:
egress-policy: audit
- name: Checkout PR
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup GitHub App Bot
if: github.actor != 'dependabot[bot]'
@@ -170,14 +144,13 @@ jobs:
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Checkout PR
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
repository: ${{ needs.check-comment.outputs.pr_repository }}
ref: ${{ needs.check-comment.outputs.pr_ref }}
ref: refs/pull/${{ needs.check-comment.outputs.pr_number }}/merge
token: ${{ steps.setup-bot.outputs.token }}
- name: Set up JDK
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "17"
distribution: "temurin"
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
egress-policy: audit
- name: Checkout PR
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup GitHub App Bot
if: github.actor != 'dependabot[bot]'
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup GitHub App Bot
id: setup-bot
+67 -61
View File
@@ -1,9 +1,11 @@
name: Build and Test Workflow
on:
pull_request:
branches: ["main", "V2", "V2-gha"]
workflow_dispatch:
# push:
# branches: ["main"]
pull_request:
branches: ["main"]
# cancel in-progress jobs if a new job is triggered
# This is useful to avoid running multiple builds for the same branch if a new commit is pushed
@@ -25,52 +27,60 @@ jobs:
name: detect what files changed
runs-on: ubuntu-latest
timeout-minutes: 3
# Map a step output to a job output
outputs:
build: ${{ steps.changes.outputs.build }}
app: ${{ steps.changes.outputs.app }}
project: ${{ steps.changes.outputs.project }}
openapi: ${{ steps.changes.outputs.openapi }}
steps:
- uses: actions/checkout@v4.3.0
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Check for file changes
uses: dorny/paths-filter@v3.0.2
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
with:
filters: .github/config/.files.yaml
filters: ".github/config/.files.yaml"
build:
runs-on: ubuntu-latest
permissions:
actions: read
security-events: write
strategy:
fail-fast: false
matrix:
jdk-version: [17, 21]
spring-security: [true, false]
steps:
- name: Harden Runner
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up JDK ${{ matrix.jdk-version }}
uses: actions/setup-java@v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: ${{ matrix.jdk-version }}
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4.4.2
uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2
with:
gradle-version: 8.14
- name: Build with Gradle and spring security ${{ matrix.spring-security }}
run: ./gradlew clean build -PnoSpotless
run: ./gradlew clean build
env:
DISABLE_ADDITIONAL_FEATURES: ${{ matrix.spring-security }}
- name: Check Test Reports Exist
id: check-reports
if: always()
run: |
declare -a dirs=(
@@ -81,83 +91,71 @@ jobs:
"app/proprietary/build/reports/tests/"
"app/proprietary/build/test-results/"
)
missing_reports=()
for dir in "${dirs[@]}"; do
if [ ! -d "$dir" ]; then
echo "Missing $dir"
exit 1
missing_reports+=("$dir")
fi
done
if [ ${#missing_reports[@]} -gt 0 ]; then
echo "ERROR: The following required test report directories are missing:"
printf '%s\n' "${missing_reports[@]}"
exit 1
fi
echo "All required test report directories are present"
- name: Upload Test Reports
if: always()
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: test-reports-jdk-${{ matrix.jdk-version }}-spring-security-${{ matrix.spring-security }}
path: |
app/**/build/reports/tests/
app/**/build/test-results/
app/**/build/reports/problems/
app/core/build/reports/tests/
app/core/build/test-results/
app/core/build/reports/problems/
app/common/build/reports/tests/
app/common/build/test-results/
app/common/build/reports/problems/
app/proprietary/build/reports/tests/
app/proprietary/build/test-results/
app/proprietary/build/reports/problems/
build/reports/problems/
retention-days: 3
if-no-files-found: warn
check-generateOpenApiDocs:
if: needs.files-changed.outputs.openapi == 'true'
needs: [files-changed]
needs: [files-changed, build]
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@v2.13.0
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up JDK 17
uses: actions/setup-java@v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "17"
distribution: "temurin"
- uses: gradle/actions/setup-gradle@v4.4.2
- name: Setup Gradle
uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2
- name: Generate OpenAPI documentation
run: ./gradlew :stirling-pdf:generateOpenApiDocs
env:
DISABLE_ADDITIONAL_FEATURES: true
- name: Upload OpenAPI Documentation
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: openapi-docs
path: ./SwaggerDoc.json
frontend-validation:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@v2.12.2
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@v4.2.2
- name: Set up Node.js
uses: actions/setup-node@v4.1.0
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Install frontend dependencies
run: cd frontend && npm ci
- name: Build frontend
run: cd frontend && npm run build
- name: Run frontend tests
run: cd frontend && npm run test -- --run
- name: Upload frontend build artifacts
uses: actions/upload-artifact@v4.6.2
with:
name: frontend-build
path: frontend/dist/
retention-days: 3
check-licence:
if: needs.files-changed.outputs.build == 'true'
needs: [files-changed, build]
@@ -167,21 +165,29 @@ jobs:
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up JDK 17
uses: actions/setup-java@v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "17"
distribution: "temurin"
- name: check the licenses for compatibility
- name: Check licenses for compatibility
run: ./gradlew clean checkLicense
- name: FAILED - check the licenses for compatibility
env:
DISABLE_ADDITIONAL_FEATURES: false
STIRLING_PDF_DESKTOP_UI: true
- name: FAILED - Check licenses for compatibility
if: failure()
uses: actions/upload-artifact@v4.6.2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: dependencies-without-allowed-license.json
path: build/reports/dependency-license/dependencies-without-allowed-license.json
path: |
build/reports/dependency-license/dependencies-without-allowed-license.json
retention-days: 3
docker-compose-tests:
@@ -210,10 +216,10 @@ jobs:
egress-policy: audit
- name: Checkout Repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Java 17
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "17"
distribution: "temurin"
@@ -259,10 +265,10 @@ jobs:
egress-policy: audit
- name: Checkout Repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up JDK 17
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "17"
distribution: "temurin"
@@ -290,7 +296,7 @@ jobs:
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
file: ./docker/backend/${{ matrix.docker-rev }}
file: ./${{ matrix.docker-rev }}
push: false
cache-from: type=gha
cache-to: type=gha,mode=max
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
egress-policy: audit
- name: Checkout main branch first
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup GitHub App Bot
id: setup-bot
+2 -2
View File
@@ -22,6 +22,6 @@ jobs:
egress-policy: audit
- name: "Checkout Repository"
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: "Dependency Review"
uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1
uses: actions/dependency-review-action@595b5aeba73380359d98a5e087f648dbb0edce1b # v4.7.3
-189
View File
@@ -1,189 +0,0 @@
name: Auto V2 Deploy on Push
on:
push:
branches:
- V2
- deploy-on-v2-commit
permissions:
contents: read
jobs:
deploy-v2-on-push:
runs-on: ubuntu-latest
concurrency:
group: deploy-v2-push-V2
cancel-in-progress: true
steps:
- name: Harden Runner
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Get commit hashes for frontend and backend
id: commit-hashes
run: |
# Get last commit that touched the frontend folder, docker/frontend, or docker/compose
FRONTEND_HASH=$(git log -1 --format="%H" -- frontend/ docker/frontend/ docker/compose/ 2>/dev/null || echo "")
if [ -z "$FRONTEND_HASH" ]; then
FRONTEND_HASH="no-frontend-changes"
fi
# Get last commit that touched backend code, docker/backend, or docker/compose
BACKEND_HASH=$(git log -1 --format="%H" -- app/ docker/backend/ docker/compose/ 2>/dev/null || echo "")
if [ -z "$BACKEND_HASH" ]; then
BACKEND_HASH="no-backend-changes"
fi
echo "Frontend hash: $FRONTEND_HASH"
echo "Backend hash: $BACKEND_HASH"
echo "frontend_hash=$FRONTEND_HASH" >> $GITHUB_OUTPUT
echo "backend_hash=$BACKEND_HASH" >> $GITHUB_OUTPUT
# Short hashes for tags
if [ "$FRONTEND_HASH" = "no-frontend-changes" ]; then
echo "frontend_short=no-frontend" >> $GITHUB_OUTPUT
else
echo "frontend_short=${FRONTEND_HASH:0:8}" >> $GITHUB_OUTPUT
fi
if [ "$BACKEND_HASH" = "no-backend-changes" ]; then
echo "backend_short=no-backend" >> $GITHUB_OUTPUT
else
echo "backend_short=${BACKEND_HASH:0:8}" >> $GITHUB_OUTPUT
fi
- name: Check if frontend image exists
id: check-frontend
run: |
if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} >/dev/null 2>&1; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "Frontend image already exists, skipping build"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "Frontend image needs to be built"
fi
- name: Check if backend image exists
id: check-backend
run: |
if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} >/dev/null 2>&1; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "Backend image already exists, skipping build"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "Backend image needs to be built"
fi
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_API }}
- name: Build and push frontend image
if: steps.check-frontend.outputs.exists == 'false'
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/frontend/Dockerfile
push: true
tags: |
${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }}
${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-latest
build-args: VERSION_TAG=v2-alpha
platforms: linux/amd64
- name: Build and push backend image
if: steps.check-backend.outputs.exists == 'false'
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/backend/Dockerfile
push: true
tags: |
${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }}
${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-latest
build-args: VERSION_TAG=v2-alpha
platforms: linux/amd64
- name: Set up SSH
run: |
mkdir -p ~/.ssh/
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
chmod 600 ../private.key
- name: Deploy to VPS on port 3000
run: |
export UNIQUE_NAME=docker-compose-v2-$GITHUB_RUN_ID.yml
cat > $UNIQUE_NAME << EOF
version: '3.3'
services:
backend:
container_name: stirling-v2-backend
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }}
ports:
- "13000:8080"
volumes:
- /stirling/V2/data:/usr/share/tessdata:rw
- /stirling/V2/config:/configs:rw
- /stirling/V2/logs:/logs:rw
environment:
DISABLE_ADDITIONAL_FEATURES: "true"
SECURITY_ENABLELOGIN: "false"
SYSTEM_DEFAULTLOCALE: en-GB
UI_APPNAME: "Stirling-PDF V2"
UI_HOMEDESCRIPTION: "V2 Frontend/Backend Split"
UI_APPNAMENAVBAR: "V2 Deployment"
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "false"
SWAGGER_SERVER_URL: "https://demo.stirlingpdf.cloud"
baseUrl: "https://demo.stirlingpdf.cloud"
restart: on-failure:5
frontend:
container_name: stirling-v2-frontend
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }}
ports:
- "3000:80"
environment:
VITE_API_BASE_URL: "http://${{ secrets.VPS_HOST }}:13000"
depends_on:
- backend
restart: on-failure:5
EOF
# Copy to remote with unique name
scp -i ../private.key -o StrictHostKeyChecking=no $UNIQUE_NAME ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }}:/tmp/$UNIQUE_NAME
# SSH and rename/move atomically to avoid interference
ssh -i ../private.key -o StrictHostKeyChecking=no ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << ENDSSH
mkdir -p /stirling/V2/{data,config,logs}
mv /tmp/$UNIQUE_NAME /stirling/V2/docker-compose.yml
cd /stirling/V2
docker-compose down || true
docker-compose pull
docker-compose up -d
docker system prune -af --volumes || true
docker image prune -af --filter "until=336h" --filter "label!=keep=true" || true
ENDSSH
- name: Cleanup temporary files
if: always()
run: |
rm -f ../private.key
@@ -1,217 +0,0 @@
name: Frontend License Report Workflow
on:
push:
branches:
- V2
paths:
- "frontend/package.json"
- "frontend/package-lock.json"
- "frontend/scripts/generate-licenses.js"
pull_request:
branches:
- V2
paths:
- "frontend/package.json"
- "frontend/package-lock.json"
- "frontend/scripts/generate-licenses.js"
permissions:
contents: read
jobs:
generate-frontend-license-report:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
repository-projects: write # Required for enabling automerge
steps:
- name: Harden Runner
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
with:
egress-policy: audit
- name: Check out code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- name: Setup GitHub App Bot
id: setup-bot
uses: ./.github/actions/setup-bot
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Set up Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: '18'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Install frontend dependencies
working-directory: frontend
run: npm ci
- name: Generate frontend license report
working-directory: frontend
run: npm run generate-licenses
- name: Check for license warnings
run: |
if [ -f "frontend/src/assets/license-warnings.json" ]; then
echo "LICENSE_WARNINGS_EXIST=true" >> $GITHUB_ENV
else
echo "LICENSE_WARNINGS_EXIST=false" >> $GITHUB_ENV
fi
# PR Event: Check licenses and comment on PR
- name: Delete previous license check comments
if: github.event_name == 'pull_request'
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ steps.setup-bot.outputs.token }}
script: |
const { owner, repo } = context.repo;
const prNumber = context.issue.number;
// Get all comments on the PR
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number: prNumber,
per_page: 100
});
// Filter for license check comments
const licenseComments = comments.filter(comment =>
comment.body.includes('## ✅ Frontend License Check Passed') ||
comment.body.includes('## ❌ Frontend License Check Failed')
);
// Delete old license check comments
for (const comment of licenseComments) {
console.log(`Deleting old license check comment: ${comment.id}`);
await github.rest.issues.deleteComment({
owner,
repo,
comment_id: comment.id
});
}
- name: Comment on PR - License Check Results
if: github.event_name == 'pull_request'
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ steps.setup-bot.outputs.token }}
script: |
const { owner, repo } = context.repo;
const prNumber = context.issue.number;
const hasWarnings = process.env.LICENSE_WARNINGS_EXIST === 'true';
let commentBody;
if (hasWarnings) {
// Read warnings file to get specific issues
const fs = require('fs');
let warningDetails = '';
try {
const warnings = JSON.parse(fs.readFileSync('frontend/src/assets/license-warnings.json', 'utf8'));
warningDetails = warnings.warnings.map(w => `- ${w.message}`).join('\n');
} catch (e) {
warningDetails = 'Unable to read warning details';
}
commentBody = `## ❌ Frontend License Check Failed
The frontend license check has detected compatibility warnings that require review:
${warningDetails}
**Action Required:** Please review these licenses to ensure they are acceptable for your use case before merging.
_This check will fail the PR until license issues are resolved._`;
} else {
commentBody = `## ✅ Frontend License Check Passed
All frontend licenses have been validated and no compatibility warnings were detected.
The frontend license report has been updated successfully.`;
}
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: commentBody
});
- name: Fail workflow if license warnings exist (PR only)
if: github.event_name == 'pull_request' && env.LICENSE_WARNINGS_EXIST == 'true'
run: |
echo "❌ License warnings detected. Failing the workflow."
exit 1
# Push Event: Commit license files and create PR
- name: Commit changes (Push only)
if: github.event_name == 'push'
run: |
git add frontend/src/assets/3rdPartyLicenses.json
# Note: Do NOT commit license-warnings.json - it's only for PR review
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
- name: Prepare PR body (Push only)
if: github.event_name == 'push'
run: |
PR_BODY="Auto-generated by ${{ steps.setup-bot.outputs.app-slug }}[bot]
This PR updates the frontend license report based on changes to package.json dependencies."
if [ "${{ env.LICENSE_WARNINGS_EXIST }}" = "true" ]; then
PR_BODY="$PR_BODY
## ⚠️ License Compatibility Warnings
The following licenses may require review for corporate compatibility:
$(cat frontend/src/assets/license-warnings.json | jq -r '.warnings[].message')
Please review these licenses to ensure they are acceptable for your use case."
fi
echo "PR_BODY<<EOF" >> $GITHUB_ENV
echo "$PR_BODY" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Create Pull Request (Push only)
id: cpr
if: github.event_name == 'push' && env.CHANGES_DETECTED == 'true'
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ steps.setup-bot.outputs.token }}
commit-message: "Update Frontend 3rd Party Licenses"
committer: ${{ steps.setup-bot.outputs.committer }}
author: ${{ steps.setup-bot.outputs.committer }}
signoff: true
branch: update-frontend-3rd-party-licenses
base: V2
title: "Update Frontend 3rd Party Licenses"
body: ${{ env.PR_BODY }}
labels: Licenses,github-actions,frontend
draft: false
delete-branch: true
sign-commits: true
- name: Enable Pull Request Automerge (Push only)
if: github.event_name == 'push' && steps.cpr.outputs.pull-request-operation == 'created' && env.LICENSE_WARNINGS_EXIST == 'false'
run: gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}"
env:
GH_TOKEN: ${{ steps.setup-bot.outputs.token }}
- name: Add review required label (Push only)
if: github.event_name == 'push' && steps.cpr.outputs.pull-request-operation == 'created' && env.LICENSE_WARNINGS_EXIST == 'true'
run: gh pr edit "${{ steps.cpr.outputs.pull-request-number }}" --add-label "license-review-required"
env:
GH_TOKEN: ${{ steps.setup-bot.outputs.token }}
+5 -2
View File
@@ -36,7 +36,7 @@ jobs:
egress-policy: audit
- name: Check out code
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
@@ -48,7 +48,7 @@ jobs:
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Set up JDK 17
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "17"
distribution: "temurin"
@@ -58,6 +58,9 @@ jobs:
- name: Check licenses for compatibility
run: ./gradlew clean checkLicense
env:
DISABLE_ADDITIONAL_FEATURES: false
STIRLING_PDF_DESKTOP_UI: true
- name: Upload artifact on failure
if: failure()
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
egress-policy: audit
- name: Check out the repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Run Labeler
uses: crazy-max/ghaction-github-labeler@24d110aa46a59976b8a7f35518cb7f14f434c916 # v5.3.0
+6 -6
View File
@@ -25,10 +25,10 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up JDK
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
distribution: 'temurin'
java-version: '21'
@@ -64,10 +64,10 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up JDK 21
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
@@ -152,10 +152,10 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up JDK 21
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
+2 -2
View File
@@ -22,7 +22,7 @@ jobs:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
@@ -48,7 +48,7 @@ jobs:
continue-on-error: true
- name: Set up JDK
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: 17
distribution: "temurin"
+2 -2
View File
@@ -34,10 +34,10 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up JDK 17
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "17"
distribution: "temurin"
+2 -2
View File
@@ -27,10 +27,10 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up JDK 17
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "17"
distribution: "temurin"
+2 -2
View File
@@ -39,7 +39,7 @@ jobs:
egress-policy: audit
- name: "Checkout code"
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
@@ -74,6 +74,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@76621b61decf072c1cee8dd1ce2d2a82d33c17ed # v3.29.5
uses: github/codeql-action/upload-sarif@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.29.5
with:
sarif_file: results.sarif
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
+2 -2
View File
@@ -30,10 +30,10 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up JDK 17
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "17"
distribution: "temurin"
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup GitHub App Bot
id: setup-bot
+25 -4
View File
@@ -29,10 +29,10 @@ jobs:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up JDK
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: '17'
distribution: 'temurin'
@@ -116,8 +116,25 @@ jobs:
docker-compose up -d
EOF
files-changed:
if: always()
name: detect what files changed
runs-on: ubuntu-latest
timeout-minutes: 3
outputs:
frontend: ${{ steps.changes.outputs.frontend }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Check for file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
with:
filters: ".github/config/.files.yaml"
test:
needs: deploy
if: needs.files-changed.outputs.frontend == 'true'
needs: [deploy, files-changed]
runs-on: ubuntu-latest
steps:
@@ -126,18 +143,20 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Run TestDriver.ai
uses: testdriverai/action@f0d0f45fdd684db628baa843fe9313f3ca3a8aa8 #1.1.3
with:
key: ${{secrets.TESTDRIVER_API_KEY}}
prerun: |
cd frontend
npm install
npm run build
npm install dashcam-chrome --save
@@ -167,6 +186,7 @@ jobs:
sudo chmod 600 ../private.key
- name: Cleanup deployment
if: always()
run: |
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << EOF
cd /stirling/test-${{ github.sha }}
@@ -174,3 +194,4 @@ jobs:
cd /stirling
rm -rf test-${{ github.sha }}
EOF
continue-on-error: true # Ensure cleanup runs even if previous steps fail
+3 -3
View File
@@ -27,7 +27,6 @@ clientWebUI/
!cucumber/exampleFiles/
!cucumber/exampleFiles/example_html.zip
exampleYmlFiles/stirling/
/stirling/
/testing/file_snapshots
SwaggerDoc.json
@@ -197,9 +196,10 @@ id_ed25519.pub
.pytest_cache
.ipynb_checkpoints
**/jcef-bundle/
# node_modules
node_modules/
# weasyPrint
**/LOCAL_APPDATA_FONTCONFIG_CACHE/**
-224
View File
@@ -1,224 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Common Development Commands
### Build and Test
- **Build project**: `./gradlew clean build`
- **Run locally**: `./gradlew bootRun`
- **Full test suite**: `./test.sh` (builds all Docker variants and runs comprehensive tests)
- **Code formatting**: `./gradlew spotlessApply` (runs automatically before compilation)
### Docker Development
- **Build ultra-lite**: `docker build -t stirlingtools/stirling-pdf:latest-ultra-lite -f ./Dockerfile.ultra-lite .`
- **Build standard**: `docker build -t stirlingtools/stirling-pdf:latest -f ./Dockerfile .`
- **Build fat version**: `docker build -t stirlingtools/stirling-pdf:latest-fat -f ./Dockerfile.fat .`
- **Example compose files**: Located in `exampleYmlFiles/` directory
### Security Mode Development
Set `DOCKER_ENABLE_SECURITY=true` environment variable to enable security features during development. This is required for testing the full version locally.
### Frontend Development
- **Frontend dev server**: `cd frontend && npm run dev` (requires backend on localhost:8080)
- **Tech Stack**: Vite + React + TypeScript + Mantine UI + TailwindCSS
- **Proxy Configuration**: Vite proxies `/api/*` calls to backend (localhost:8080)
- **Build Process**: DO NOT run build scripts manually - builds are handled by CI/CD pipelines
- **Package Installation**: DO NOT run npm install commands - package management handled separately
- **Deployment Options**:
- **Desktop App**: `npm run tauri-build` (native desktop application)
- **Web Server**: `npm run build` then serve dist/ folder
- **Development**: `npm run tauri-dev` for desktop dev mode
#### Multi-Tool Workflow Architecture
Frontend designed for **stateful document processing**:
- Users upload PDFs once, then chain tools (split → merge → compress → view)
- File state and processing results persist across tool switches
- No file reloading between tools - performance critical for large PDFs (up to 100GB+)
#### FileContext - Central State Management
**Location**: `src/contexts/FileContext.tsx`
- **Active files**: Currently loaded PDFs and their variants
- **Tool navigation**: Current mode (viewer/pageEditor/fileEditor/toolName)
- **Memory management**: PDF document cleanup, blob URL lifecycle, Web Worker management
- **IndexedDB persistence**: File storage with thumbnail caching
- **Preview system**: Tools can preview results (e.g., Split → Viewer → back to Split) without context pollution
**Critical**: All file operations go through FileContext. Don't bypass with direct file handling.
#### Processing Services
- **enhancedPDFProcessingService**: Background PDF parsing and manipulation
- **thumbnailGenerationService**: Web Worker-based with main-thread fallback
- **fileStorage**: IndexedDB with LRU cache management
#### Memory Management Strategy
**Why manual cleanup exists**: Large PDFs (up to 100GB+) through multiple tools accumulate:
- PDF.js documents that need explicit .destroy() calls
- Blob URLs from tool outputs that need revocation
- Web Workers that need termination
Without cleanup: browser crashes with memory leaks.
#### Tool Development
**Architecture**: Modular hook-based system with clear separation of concerns:
- **useToolOperation** (`frontend/src/hooks/tools/shared/useToolOperation.ts`): Main orchestrator hook
- Coordinates all tool operations with consistent interface
- Integrates with FileContext for operation tracking
- Handles validation, error handling, and UI state management
- **Supporting Hooks**:
- **useToolState**: UI state management (loading, progress, error, files)
- **useToolApiCalls**: HTTP requests and file processing
- **useToolResources**: Blob URLs, thumbnails, ZIP downloads
- **Utilities**:
- **toolErrorHandler**: Standardized error extraction and i18n support
- **toolResponseProcessor**: API response handling (single/zip/custom)
- **toolOperationTracker**: FileContext integration utilities
**Three Tool Patterns**:
**Pattern 1: Single-File Tools** (Individual processing)
- Backend processes one file per API call
- Set `multiFileEndpoint: false`
- Examples: Compress, Rotate
```typescript
return useToolOperation({
operationType: 'compress',
endpoint: '/api/v1/misc/compress-pdf',
buildFormData: (params, file: File) => { /* single file */ },
multiFileEndpoint: false,
filePrefix: 'compressed_'
});
```
**Pattern 2: Multi-File Tools** (Batch processing)
- Backend accepts `MultipartFile[]` arrays in single API call
- Set `multiFileEndpoint: true`
- Examples: Split, Merge, Overlay
```typescript
return useToolOperation({
operationType: 'split',
endpoint: '/api/v1/general/split-pages',
buildFormData: (params, files: File[]) => { /* all files */ },
multiFileEndpoint: true,
filePrefix: 'split_'
});
```
**Pattern 3: Complex Tools** (Custom processing)
- Tools with complex routing logic or non-standard processing
- Provide `customProcessor` for full control
- Examples: Convert, OCR
```typescript
return useToolOperation({
operationType: 'convert',
customProcessor: async (params, files) => { /* custom logic */ },
filePrefix: 'converted_'
});
```
**Benefits**:
- **No Timeouts**: Operations run until completion (supports 100GB+ files)
- **Consistent**: All tools follow same pattern and interface
- **Maintainable**: Single responsibility hooks, easy to test and modify
- **i18n Ready**: Built-in internationalization support
- **Type Safe**: Full TypeScript support with generic interfaces
- **Memory Safe**: Automatic resource cleanup and blob URL management
## Architecture Overview
### Project Structure
- **Backend**: Spring Boot application with Thymeleaf templating
- **Frontend**: React-based SPA in `/frontend` directory (Thymeleaf templates fully replaced)
- **File Storage**: IndexedDB for client-side file persistence and thumbnails
- **Internationalization**: JSON-based translations (converted from backend .properties)
- **PDF Processing**: PDFBox for core PDF operations, LibreOffice for conversions, PDF.js for client-side rendering
- **Security**: Spring Security with optional authentication (controlled by `DOCKER_ENABLE_SECURITY`)
- **Configuration**: YAML-based configuration with environment variable overrides
### Controller Architecture
- **API Controllers** (`src/main/java/.../controller/api/`): REST endpoints for PDF operations
- Organized by function: converters, security, misc, pipeline
- Follow pattern: `@RestController` + `@RequestMapping("/api/v1/...")`
- **Web Controllers** (`src/main/java/.../controller/web/`): Serve Thymeleaf templates
- Pattern: `@Controller` + return template names
### Key Components
- **SPDFApplication.java**: Main application class with desktop UI and browser launching logic
- **ConfigInitializer**: Handles runtime configuration and settings files
- **Pipeline System**: Automated PDF processing workflows via `PipelineController`
- **Security Layer**: Authentication, authorization, and user management (when enabled)
### Component Architecture
- **React Components**: Located in `frontend/src/components/` and `frontend/src/tools/`
- **Static Assets**: CSS, JS, and resources in `src/main/resources/static/` (legacy) + `frontend/public/` (modern)
- **Internationalization**:
- Backend: `messages_*.properties` files
- Frontend: JSON files in `frontend/public/locales/` (converted from .properties)
- Conversion Script: `scripts/convert_properties_to_json.py`
### Configuration Modes
- **Ultra-lite**: Basic PDF operations only
- **Standard**: Full feature set
- **Fat**: Pre-downloaded dependencies for air-gapped environments
- **Security Mode**: Adds authentication, user management, and enterprise features
### Testing Strategy
- **Integration Tests**: Cucumber tests in `testing/cucumber/`
- **Docker Testing**: `test.sh` validates all Docker variants
- **Manual Testing**: No unit tests currently - relies on UI and API testing
## Development Workflow
1. **Local Development**:
- Backend: `./gradlew bootRun` (runs on localhost:8080)
- Frontend: `cd frontend && npm run dev` (runs on localhost:5173, proxies to backend)
2. **Docker Testing**: Use `./test.sh` before submitting PRs
3. **Code Style**: Spotless enforces Google Java Format automatically
4. **Translations**:
- Backend: Use helper scripts in `/scripts` for multi-language updates
- Frontend: Update JSON files in `frontend/public/locales/` or use conversion script
5. **Documentation**: API docs auto-generated and available at `/swagger-ui/index.html`
## Frontend Architecture Status
- **Core Status**: React SPA architecture complete with multi-tool workflow support
- **State Management**: FileContext handles all file operations and tool navigation
- **File Processing**: Production-ready with memory management for large PDF workflows (up to 100GB+)
- **Tool Integration**: Modular hook architecture with `useToolOperation` orchestrator
- Individual hooks: `useToolState`, `useToolApiCalls`, `useToolResources`
- Utilities: `toolErrorHandler`, `toolResponseProcessor`, `toolOperationTracker`
- Pattern: Each tool creates focused operation hook, UI consumes state/actions
- **Preview System**: Tool results can be previewed without polluting file context (Split tool example)
- **Performance**: Web Worker thumbnails, IndexedDB persistence, background processing
## Important Notes
- **Java Version**: Minimum JDK 17, supports and recommends JDK 21
- **Lombok**: Used extensively - ensure IDE plugin is installed
- **Desktop Mode**: Set `STIRLING_PDF_DESKTOP_UI=true` for desktop application mode
- **File Persistence**:
- **Backend**: Designed to be stateless - files are processed in memory/temp locations only
- **Frontend**: Uses IndexedDB for client-side file storage and caching (with thumbnails)
- **Security**: When `DOCKER_ENABLE_SECURITY=false`, security-related classes are excluded from compilation
- **FileContext**: All file operations MUST go through FileContext - never bypass with direct File handling
- **Memory Management**: Manual cleanup required for PDF.js documents and blob URLs - don't remove cleanup code
- **Tool Development**: New tools should follow `useToolOperation` hook pattern (see `useCompressOperation.ts`)
- **Performance Target**: Must handle PDFs up to 100GB+ without browser crashes
- **Preview System**: Tools can preview results without polluting main file context (see Split tool implementation)
## Communication Style
- Be direct and to the point
- No apologies or conversational filler
- Answer questions directly without preamble
- Explain reasoning concisely when asked
- Avoid unnecessary elaboration
## Decision Making
- Ask clarifying questions before making assumptions
- Stop and ask when uncertain about project-specific details
- Confirm approach before making structural changes
- Request guidance on preferences (cross-platform vs specific tools, etc.)
- Verify understanding of requirements before proceeding
+1 -1
View File
@@ -5,7 +5,7 @@
The newly introduced feature enhances the application with robust database backup and import capabilities. This feature is designed to ensure data integrity and provide a straightforward way to manage database backups. Here's how it works:
1. Automatic Backup Creation
- The system automatically creates a database backup every day at midnight. This ensures that there is always a recent backup available, minimizing the risk of data loss.
- The system automatically creates a database backup on a configurable schedule (default: daily at midnight via `system.databaseBackup.cron`). This ensures that there is always a recent backup available, minimizing the risk of data loss.
2. Manual Backup Export
- Admin actions that modify the user database trigger a manual export of the database. This keeps the backup up-to-date with the latest changes and provides an extra layer of data security.
3. Importing Database Backups
-692
View File
@@ -1,692 +0,0 @@
# Stirling-PDF Developer Guide
## 1. Introduction
Stirling-PDF is a robust, locally hosted, web-based PDF manipulation tool. **Stirling 2.0** represents a complete frontend rewrite, replacing the legacy Thymeleaf-based UI with a modern React SPA (Single Page Application).
This guide focuses on developing for Stirling 2.0, including both the React frontend and Spring Boot backend development workflows.
## 2. Project Overview
**Stirling 2.0** is built using:
**Backend:**
- Spring Boot (Java 17+, JDK 21 recommended)
- PDFBox for core PDF operations
- LibreOffice for document conversions
- qpdf for PDF optimization
- Spring Security (optional, controlled by `DOCKER_ENABLE_SECURITY`)
- Lombok for reducing boilerplate code
**Frontend (React SPA):**
- React + TypeScript
- Vite for build tooling and development server
- Mantine UI component library
- TailwindCSS for styling
- PDF.js for client-side PDF rendering
- PDF-LIB.js for client-side PDF manipulation
- IndexedDB for client-side file storage and thumbnails
- i18next for internationalization
**Infrastructure:**
- Docker for containerization
- Gradle for build management
**Legacy (reference only during development):**
- Thymeleaf templates (being completely replaced in 2.0)
## 3. Development Environment Setup
### Prerequisites
- Docker
- Git
- Java JDK 17 or later (JDK 21 recommended)
- Node.js 18+ and npm (required for frontend development)
- Gradle 7.0 or later (Included within the repo)
### Setup Steps
1. Clone the repository:
```bash
git clone https://github.com/Stirling-Tools/Stirling-PDF.git
cd Stirling-PDF
```
2. Install Docker and JDK17 if not already installed.
3. Install a recommended Java IDE such as Eclipse, IntelliJ, or VSCode
1. Only VSCode
1. Open VS Code.
2. When prompted, install the recommended extensions.
3. Alternatively, open the command palette (`Ctrl + Shift + P` or `Cmd + Shift + P` on macOS) and run:
```sh
Extensions: Show Recommended Extensions
```
4. Install the required extensions from the list.
4. Lombok Setup
Stirling-PDF uses Lombok to reduce boilerplate code. Some IDEs, like Eclipse, don't support Lombok out of the box. To set up Lombok in your development environment:
Visit the [Lombok website](https://projectlombok.org/setup/) for installation instructions specific to your IDE.
5. Add environment variable
For local testing, you should generally be testing the full 'Security' version of Stirling PDF. To do this, you must add the environment flag DISABLE_ADDITIONAL_FEATURES=false to your system and/or IDE build/run step.
5. **Frontend Setup (Required for Stirling 2.0)**
Navigate to the frontend directory and install dependencies using npm.
## 4. Stirling 2.0 Development Workflow
### Frontend Development (React)
The frontend is a React SPA that runs independently during development:
1. **Start the backend**: Run the Spring Boot application (serves API endpoints on localhost:8080)
2. **Start the frontend dev server**: Navigate to the frontend directory and run the development server (serves UI on localhost:5173)
3. **Development flow**: The Vite dev server automatically proxies API calls to the backend
### File Storage Architecture
Stirling 2.0 uses client-side file storage:
- **IndexedDB**: Stores files locally in the browser with automatic thumbnail generation
- **PDF.js**: Handles client-side PDF rendering and processing
- **URL Parameters**: Support for deep linking and tool state persistence
### Legacy Code Reference
The existing Thymeleaf templates remain in the codebase during development as reference material but will be completely removed for the 2.0 release.
## 5. Project Structure
```bash
Stirling-PDF/
├── .github/ # GitHub-specific files (workflows, issue templates)
├── configs/ # Configuration files used by stirling at runtime (generated at runtime)
├── frontend/ # React SPA frontend (Stirling 2.0)
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── tools/ # Tool-specific React components
│ │ ├── hooks/ # Custom React hooks
│ │ ├── services/ # API and utility services
│ │ ├── types/ # TypeScript type definitions
│ │ └── utils/ # Utility functions
│ ├── public/
│ │ └── locales/ # Internationalization files (JSON)
│ ├── package.json # Frontend dependencies
│ └── vite.config.ts # Vite configuration
├── customFiles/ # Custom static files and templates (generated at runtime used to replace existing files)
├── docs/ # Documentation files
├── exampleYmlFiles/ # Example YAML configuration files
├── images/ # Image assets
├── pipeline/ # Pipeline-related files (generated at runtime)
├── scripts/ # Utility scripts
├── src/ # Source code
│ ├── main/
│ │ ├── java/
│ │ │ └── stirling/
│ │ │ └── software/
│ │ │ └── SPDF/
│ │ │ ├── config/
│ │ │ ├── controller/
│ │ │ ├── model/
│ │ │ ├── repository/
│ │ │ ├── service/
│ │ │ └── utils/
│ │ └── resources/
│ │ ├── static/ # Legacy static assets (reference only)
│ │ │ ├── css/
│ │ │ ├── js/
│ │ │ └── pdfjs/
│ │ └── templates/ # Legacy Thymeleaf templates (reference only)
│ └── test/
├── testing/ # Cucumber and integration tests
│ └── cucumber/ # Cucumber test files
├── build.gradle # Gradle build configuration
├── Dockerfile # Main Dockerfile
├── Dockerfile.ultra-lite # Dockerfile for ultra-lite version
├── Dockerfile.fat # Dockerfile for fat version
├── docker-compose.yml # Docker Compose configuration
└── test.sh # Test script to deploy all docker versions and run cuke tests
```
## 6. Docker-based Development
Stirling-PDF offers several Docker versions:
- Full: All features included
- Ultra-Lite: Basic PDF operations only
- Fat: Includes additional libraries and fonts predownloaded
### Example Docker Compose Files
Stirling-PDF provides several example Docker Compose files in the `exampleYmlFiles` directory, such as:
- `docker-compose-latest.yml`: Latest version without login and security features
- `docker-compose-latest-security.yml`: Latest version with login and security features enabled
- `docker-compose-latest-fat-security.yml`: Fat version with login and security features enabled
These files provide pre-configured setups for different scenarios. For example, here's a snippet from `docker-compose-latest-security.yml`:
```yaml
services:
stirling-pdf:
container_name: Stirling-PDF-Security
image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest
deploy:
resources:
limits:
memory: 4G
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"]
interval: 5s
timeout: 10s
retries: 16
ports:
- "8080:8080"
volumes:
- ./stirling/latest/data:/usr/share/tessdata:rw
- ./stirling/latest/config:/configs:rw
- ./stirling/latest/logs:/logs:rw
environment:
DISABLE_ADDITIONAL_FEATURES: "false"
SECURITY_ENABLELOGIN: "true"
PUID: 1002
PGID: 1002
UMASK: "022"
SYSTEM_DEFAULTLOCALE: en-US
UI_APPNAME: Stirling-PDF
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security
UI_APPNAMENAVBAR: Stirling-PDF Latest
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "true"
SHOW_SURVEY: "true"
restart: on-failure:5
```
To use these example files, copy the desired file to your project root and rename it to `docker-compose.yml`, or specify the file explicitly when running Docker Compose:
```bash
docker-compose -f exampleYmlFiles/docker-compose-latest-security.yml up
```
### Building Docker Images
Stirling-PDF uses different Docker images for various configurations. The build process is controlled by environment variables and uses specific Dockerfile variants. Here's how to build the Docker images:
1. Set the security environment variable:
```bash
export DISABLE_ADDITIONAL_FEATURES=true # or false for to enable login and security features for builds
```
2. Build the project with Gradle:
```bash
./gradlew clean build
```
3. Build the Docker images:
For the latest version:
```bash
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest -f ./Dockerfile .
```
For the ultra-lite version:
```bash
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-ultra-lite -f ./Dockerfile.ultra-lite .
```
For the fat version (with login and security features enabled):
```bash
export DISABLE_ADDITIONAL_FEATURES=false
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-fat -f ./Dockerfile.fat .
```
Note: The `--no-cache` and `--pull` flags ensure that the build process uses the latest base images and doesn't use cached layers, which is useful for testing and ensuring reproducible builds. however to improve build times these can often be removed depending on your usecase
## 7. Testing
### Comprehensive Testing Script
Stirling-PDF provides a `test.sh` script in the root directory. This script builds all versions of Stirling-PDF, checks that each version works, and runs Cucumber tests. It's recommended to run this script before submitting a final pull request.
To run the test script:
```bash
./test.sh
```
This script performs the following actions:
1. Builds all Docker images (full, ultra-lite, fat).
2. Runs each version to ensure it starts correctly.
3. Executes Cucumber tests against the main version and ensures feature compatibility. In the event these tests fail, your PR will not be merged.
Note: The `test.sh` script will run automatically when you raise a PR. However, it's recommended to run it locally first to save resources and catch any issues early.
### Full Testing with Docker
1. Build and run the Docker container per the above instructions:
2. Access the application at `http://localhost:8080` and manually test all features developed.
### Frontend Development Testing (Stirling 2.0)
For React frontend development:
1. Start the backend: Run the Spring Boot application to serve API endpoints on localhost:8080
2. Start the frontend dev server: Navigate to the frontend directory and run the development server on localhost:5173
3. The Vite dev server automatically proxies API calls to the backend
4. Test React components, UI interactions, and IndexedDB file operations using browser developer tools
### Local Testing (Java and UI Components)
For quick iterations and development of Java backend, JavaScript, and UI components, you can run and test Stirling-PDF locally without Docker. This approach allows you to work on and verify changes to:
- Java backend logic
- RESTful API endpoints
- JavaScript functionality
- User interface components and styling
- Thymeleaf templates
To run Stirling-PDF locally:
1. Compile and run the project using built-in IDE methods or by running:
```bash
./gradlew bootRun
```
2. Access the application at `http://localhost:8080` in your web browser.
3. Manually test the features you're working on through the UI.
4. For API changes, use tools like Postman or curl to test endpoints directly.
Important notes:
- Local testing doesn't include features that depend on external tools like qpdf, LibreOffice, or Python scripts.
- There are currently no automated unit tests. All testing is done manually through the UI or API calls. (You are welcome to add JUnits!)
- Always verify your changes in the full Docker environment before submitting pull requests, as some integrations and features will only work in the complete setup.
## 8. Contributing
1. Fork the repository on GitHub.
2. Create a new branch for your feature or bug fix.
3. Make your changes and commit them with clear, descriptive messages and ensure any documentation is updated related to your changes.
4. Test your changes thoroughly in the Docker environment.
5. Run the `test.sh` script to ensure all versions build correctly and pass the Cucumber tests:
```bash
./test.sh
```
6. Push your changes to your fork.
7. Submit a pull request to the main repository.
8. See additional [contributing guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md).
When you raise a PR:
- The `test.sh` script will run automatically against your PR.
- The PR checks will verify versioning and dependency updates.
- Documentation will be automatically updated for dependency changes.
- Security issues will be checked using Snyk and PixeeBot.
Address any issues that arise from these checks before finalizing your pull request.
## 9. API Documentation
API documentation is available at `/swagger-ui/index.html` when running the application. You can also view the latest API documentation [here](https://app.swaggerhub.com/apis-docs/Stirling-Tools/Stirling-PDF/).
## 10. Customization
Stirling-PDF can be customized through environment variables or a `settings.yml` file. Key customization options include:
- Application name and branding
- Security settings
- UI customization
- Endpoint management
When using Docker, pass environment variables using the `-e` flag or in your `docker-compose.yml` file.
Example:
```bash
docker run -p 8080:8080 -e APP_NAME="My PDF Tool" stirling-pdf:full
```
Refer to the main README for a full list of customization options.
## 11. Language Translations
For managing language translations that affect multiple files, Stirling-PDF provides a helper script:
```bash
/scripts/replace_translation_line.sh
```
This script helps you make consistent replacements across language files.
When contributing translations:
1. Use the helper script for multi-file changes.
2. Ensure all language files are updated consistently.
3. The PR checks will verify consistency in language file updates.
Remember to test your changes thoroughly to ensure they don't break any existing functionality.
## Code examples
### React Component Development (Stirling 2.0)
For Stirling 2.0, new features are built as React components instead of Thymeleaf templates:
#### Creating a New Tool Component
1. **Create the React Component:**
```typescript
// frontend/src/tools/NewTool.tsx
import { useState } from 'react';
import { Button, FileInput, Container } from '@mantine/core';
interface NewToolProps {
params: Record<string, any>;
updateParams: (updates: Record<string, any>) => void;
}
export default function NewTool({ params, updateParams }: NewToolProps) {
const [files, setFiles] = useState<File[]>([]);
const handleProcess = async () => {
// Process files using API or client-side logic
};
return (
<Container>
<FileInput
multiple
accept="application/pdf"
onChange={setFiles}
/>
<Button onClick={handleProcess}>Process</Button>
</Container>
);
}
```
2. **Add API Integration:**
```typescript
// Use existing API endpoints or create new ones
const response = await fetch('/api/v1/new-tool', {
method: 'POST',
body: formData
});
```
3. **Register in Tool Picker:**
Update the tool picker component to include the new tool with proper routing and URL parameter support.
### Legacy Reference: Overview of Thymeleaf
Thymeleaf is a server-side Java HTML template engine. It is used in Stirling-PDF to render dynamic web pages. Thymeleaf integrates heavily with Spring Boot.
### Thymeleaf overview
In Stirling-PDF, Thymeleaf is used to create HTML templates that are rendered on the server side. These templates are located in the `stirling-pdf/src/main/resources/templates` directory. Thymeleaf templates use a combination of HTML and special Thymeleaf attributes to dynamically generate content.
Some examples of this are:
```html
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
```
or
```html
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
```
Where it uses the `th:block`, `th:` indicating it's a special Thymeleaf element to be used server-side in generating the HTML, and block being the actual element type.
In this case, we are inserting the `navbar` entry within the `fragments/navbar.html` fragment into the `th:block` element.
They can be more complex, such as:
```html
<th:block th:insert="~{fragments/common :: head(title=#{pageExtracter.title}, header=#{pageExtracter.header})}"></th:block>
```
Which is the same as above but passes the parameters title and header into the fragment `common.html` to be used in its HTML generation.
Thymeleaf can also be used to loop through objects or pass things from the Java side into the HTML side.
```java
@GetMapping
public String newFeaturePage(Model model) {
model.addAttribute("exampleData", exampleData);
return "new-feature";
}
```
In the above example, if exampleData is a list of plain java objects of class Person and within it, you had id, name, age, etc. You can reference it like so
```html
<tbody>
<!-- Use th:each to iterate over the list -->
<tr th:each="person : ${exampleData}">
<td th:text="${person.id}"></td>
<td th:text="${person.name}"></td>
<td th:text="${person.age}"></td>
<td th:text="${person.email}"></td>
</tr>
</tbody>
```
This would generate n entries of tr for each person in exampleData
### Adding a New Feature to the Backend (API)
1. **Create a New Controller:**
- Create a new Java class in the `stirling-pdf/src/main/java/stirling/software/SPDF/controller/api` directory.
- Annotate the class with `@RestController` and `@RequestMapping` to define the API endpoint.
- Ensure to add API documentation annotations like `@Tag(name = "General", description = "General APIs")` and `@Operation(summary = "Crops a PDF document", description = "This operation takes an input PDF file and crops it according to the given coordinates. Input:PDF Output:PDF Type:SISO")`.
```java
package stirling.software.SPDF.controller.api;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@RestController
@RequestMapping("/api/v1/new-feature")
@Tag(name = "General", description = "General APIs")
public class NewFeatureController {
@GetMapping
@Operation(summary = "New Feature", description = "This is a new feature endpoint.")
public String newFeature() {
return "NewFeatureResponse"; // This refers to the NewFeatureResponse.html template presenting the user with the generated html from that file when they navigate to /api/v1/new-feature
}
}
```
2. **Define the Service Layer:** (Not required but often useful)
- Create a new service class in the `stirling-pdf/src/main/java/stirling/software/SPDF/service` directory.
- Implement the business logic for the new feature.
```java
package stirling.software.SPDF.service;
import org.springframework.stereotype.Service;
@Service
public class NewFeatureService {
public String getNewFeatureData() {
// Implement business logic here
return "New Feature Data";
}
}
```
2b. **Integrate the Service with the Controller:**
- Autowire the service class in the controller and use it to handle the API request.
```java
package stirling.software.SPDF.controller.api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import stirling.software.SPDF.service.NewFeatureService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@RestController
@RequestMapping("/api/v1/new-feature")
@Tag(name = "General", description = "General APIs")
public class NewFeatureController {
@Autowired
private NewFeatureService newFeatureService;
@GetMapping
@Operation(summary = "New Feature", description = "This is a new feature endpoint.")
public String newFeature() {
return newFeatureService.getNewFeatureData();
}
}
```
### Adding a New Feature to the Frontend (UI)
1. **Create a New Thymeleaf Template:**
- Create a new HTML file in the `stirling-pdf/src/main/resources/templates` directory.
- Use Thymeleaf attributes to dynamically generate content.
- Use `extract-page.html` as a base example for the HTML template, which is useful to ensure importing of the general layout, navbar, and footer.
```html
<!DOCTYPE html>
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{newFeature.title}, header=#{newFeature.header})}"></th:block>
</head>
<body>
<div id="page-container">
<div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br><br>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6 bg-card">
<div class="tool-header">
<span class="material-symbols-rounded tool-header-icon organize">upload</span>
<span class="tool-header-text" th:text="#{newFeature.header}"></span>
</div>
<form th:action="@{'/api/v1/new-feature'}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
<input type="hidden" id="customMode" name="customMode" value="">
<div class="mb-3">
<label for="featureInput" th:text="#{newFeature.prompt}"></label>
<input type="text" class="form-control" id="featureInput" name="featureInput" th:placeholder="#{newFeature.placeholder}" required>
</div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{newFeature.submit}"></button>
</form>
</div>
</div>
</div>
</div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
</body>
</html>
```
2. **Create a New Controller for the UI:**
- Create a new Java class in the `stirling-pdf/src/main/java/stirling/software/SPDF/controller/ui` directory.
- Annotate the class with `@Controller` and `@RequestMapping` to define the UI endpoint.
```java
package stirling.software.SPDF.controller.ui;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import stirling.software.SPDF.service.NewFeatureService;
@Controller
@RequestMapping("/new-feature")
public class NewFeatureUIController {
@Autowired
private NewFeatureService newFeatureService;
@GetMapping
public String newFeaturePage(Model model) {
model.addAttribute("newFeatureData", newFeatureService.getNewFeatureData());
return "new-feature";
}
}
```
3. **Update the Navigation Bar:**
- Add a link to the new feature page in the navigation bar.
- Update the `stirling-pdf/src/main/resources/templates/fragments/navbar.html` file.
```html
<li class="nav-item">
<a class="nav-link" th:href="@{'/new-feature'}">New Feature</a>
</li>
```
## Adding New Translations to Existing Language Files in Stirling-PDF
When adding a new feature or modifying existing ones in Stirling-PDF, you'll need to add new translation entries to the existing language files. Here's a step-by-step guide:
### 1. Locate Existing Language Files
Find the existing `messages.properties` files in the `stirling-pdf/src/main/resources` directory. You'll see files like:
- `messages.properties` (default, usually English)
- `messages_en_GB.properties`
- `messages_fr_FR.properties`
- `messages_de_DE.properties`
- etc.
### 2. Add New Translation Entries
Open each of these files and add your new translation entries. For example, if you're adding a new feature called "PDF Splitter",
Use descriptive, hierarchical keys (e.g., `feature.element.description`)
you might add:
```properties
pdfSplitter.title=PDF Splitter
pdfSplitter.description=Split your PDF into multiple documents
pdfSplitter.button.split=Split PDF
pdfSplitter.input.pages=Enter page numbers to split
```
Add these entries to the default GB language file and any others you wish, translating the values as appropriate for each language.
### 3. Use Translations in Thymeleaf Templates
In your Thymeleaf templates, use the `#{key}` syntax to reference the new translations:
```html
<h1 th:text="#{pdfSplitter.title}">PDF Splitter</h1>
<p th:text="#{pdfSplitter.description}">Split your PDF into multiple documents</p>
<input type="text" th:placeholder="#{pdfSplitter.input.pages}">
<button th:text="#{pdfSplitter.button.split}">Split PDF</button>
```
Remember, never hard-code text in your templates or Java code. Always use translation keys to ensure proper localization.
+18 -39
View File
@@ -1,40 +1,15 @@
# Backend Dockerfile - Java Spring Boot with all dependencies and build stage
# Build the application
FROM gradle:8.14-jdk21 AS build
COPY build.gradle .
COPY settings.gradle .
COPY gradlew .
COPY gradle gradle/
COPY app/core/build.gradle core/.
COPY app/common/build.gradle common/.
COPY app/proprietary/build.gradle proprietary/.
RUN ./gradlew build -x spotlessApply -x spotlessCheck -x test -x sonarqube || return 0
# Set the working directory
WORKDIR /app
# Copy the entire project to the working directory
COPY . .
# Build the application with DISABLE_ADDITIONAL_FEATURES=false
RUN DISABLE_ADDITIONAL_FEATURES=false \
STIRLING_PDF_DESKTOP_UI=false \
./gradlew clean build -x spotlessApply -x spotlessCheck -x test -x sonarqube
# Main stage
FROM alpine:3.22.1@sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1
# Copy necessary files
COPY scripts /scripts
COPY app/core/src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
# first /app directory is for the build stage, second is for the final image
COPY --from=build /app/app/core/build/libs/*.jar app.jar
COPY app/core/build/libs/*.jar app.jar
ARG VERSION_TAG
LABEL org.opencontainers.image.title="Stirling-PDF Backend"
LABEL org.opencontainers.image.description="Backend service for Stirling-PDF - Java Spring Boot with PDF processing capabilities"
LABEL org.opencontainers.image.title="Stirling-PDF"
LABEL org.opencontainers.image.description="A powerful locally hosted web-based PDF manipulation tool supporting 50+ operations including merging, splitting, conversion, OCR, watermarking, and more."
LABEL org.opencontainers.image.source="https://github.com/Stirling-Tools/Stirling-PDF"
LABEL org.opencontainers.image.licenses="MIT"
LABEL org.opencontainers.image.vendor="Stirling-Tools"
@@ -43,10 +18,10 @@ LABEL org.opencontainers.image.documentation="https://docs.stirlingpdf.com"
LABEL maintainer="Stirling-Tools"
LABEL org.opencontainers.image.authors="Stirling-Tools"
LABEL org.opencontainers.image.version="${VERSION_TAG}"
LABEL org.opencontainers.image.keywords="PDF, manipulation, backend, API, Spring Boot"
LABEL org.opencontainers.image.keywords="PDF, manipulation, merge, split, convert, OCR, watermark"
# Set Environment Variables
ENV DISABLE_ADDITIONAL_FEATURES=false \
ENV DISABLE_ADDITIONAL_FEATURES=true \
VERSION_TAG=$VERSION_TAG \
JAVA_BASE_OPTS="-XX:+UnlockExperimentalVMOptions -XX:MaxRAMPercentage=75 -XX:InitiatingHeapOccupancyPercent=20 -XX:+G1PeriodicGCInvokesConcurrent -XX:G1PeriodicGCInterval=10000 -XX:+UseStringDeduplication -XX:G1PeriodicGCSystemLoadThreshold=70" \
JAVA_CUSTOM_OPTS="" \
@@ -63,7 +38,8 @@ ENV DISABLE_ADDITIONAL_FEATURES=false \
TEMP=/tmp/stirling-pdf \
TMP=/tmp/stirling-pdf
# JDK for app and all dependencies
# JDK for app
RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
echo "@community https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
@@ -86,37 +62,40 @@ RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/a
# pdftohtml
poppler-utils \
# OCR MY PDF (unpaper for descew and other advanced features)
unpaper \
tesseract-ocr-data-eng \
tesseract-ocr-data-chi_sim \
tesseract-ocr-data-deu \
tesseract-ocr-data-fra \
tesseract-ocr-data-por \
ocrmypdf \
unpaper \
# CV
py3-opencv \
python3 \
ocrmypdf \
py3-pip \
py3-pillow@testing \
py3-pdf2image@testing && \
py3-pdf2image@testing \
# URW Base 35 fonts for better PDF rendering
font-urw-base35 && \
python3 -m venv /opt/venv && \
/opt/venv/bin/pip install --upgrade pip setuptools && \
/opt/venv/bin/pip install --no-cache-dir --upgrade pip setuptools && \
/opt/venv/bin/pip install --no-cache-dir --upgrade unoserver weasyprint && \
ln -s /usr/lib/libreoffice/program/uno.py /opt/venv/lib/python3.12/site-packages/ && \
ln -s /usr/lib/libreoffice/program/unohelper.py /opt/venv/lib/python3.12/site-packages/ && \
ln -s /usr/lib/libreoffice/program /opt/venv/lib/python3.12/site-packages/LibreOffice && \
mv /usr/share/tessdata /usr/share/tessdata-original && \
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /tmp/stirling-pdf /pipeline/watchedFolders /pipeline/finishedFolders && \
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /tmp/stirling-pdf && \
# Configure URW Base 35 fonts
ln -s /usr/share/fontconfig/conf.avail/69-urw-*.conf /etc/fonts/conf.d/ && \
fc-cache -f -v && \
chmod +x /scripts/* && \
chmod +x /scripts/init.sh && \
# User permissions
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /pipeline /usr/share/fonts/opentype/noto /configs /customFiles /pipeline /tmp/stirling-pdf && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline /tmp/stirling-pdf && \
chown stirlingpdfuser:stirlingpdfgroup /app.jar
EXPOSE 8080/tcp
# Set user and run command
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
CMD ["sh", "-c", "java -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/tmp/stirling-pdf -jar /app.jar & /opt/venv/bin/unoserver --port 2003 --interface 127.0.0.1"]
CMD ["sh", "-c", "java -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/tmp/stirling-pdf -jar /app.jar & /opt/venv/bin/unoserver --port 2003 --interface 127.0.0.1"]
+60
View File
@@ -0,0 +1,60 @@
# dockerfile.dev
# Basisimage: Gradle mit JDK 17 (Debian-basiert)
FROM gradle:8.14-jdk17
# Als Root-Benutzer arbeiten, um benötigte Pakete zu installieren
USER root
# Set GRADLE_HOME und füge Gradle zum PATH hinzu
ENV GRADLE_HOME=/opt/gradle
ENV PATH="$GRADLE_HOME/bin:$PATH"
# Update und Installation zusätzlicher Pakete (Debian/Ubuntu-basiert)
RUN apt-get update && apt-get install -y \
sudo \
libreoffice \
poppler-utils \
qpdf \
# settings.yml | tessdataDir: /usr/share/tesseract-ocr/5/tessdata
tesseract-ocr \
tesseract-ocr-eng \
fonts-terminus fonts-dejavu fonts-font-awesome fonts-noto fonts-noto-core fonts-noto-cjk fonts-noto-extra fonts-liberation fonts-linuxlibertine fonts-urw-base35 \
python3-uno \
python3-venv \
# ss -tln
iproute2 \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Setze die Environment Variable für setuptools
ENV SETUPTOOLS_USE_DISTUTILS=local \
STIRLING_TEMPFILES_DIRECTORY=/tmp/stirling-pdf \
TMPDIR=/tmp/stirling-pdf \
TEMP=/tmp/stirling-pdf \
TMP=/tmp/stirling-pdf
# Installation der benötigten Python-Pakete
COPY .github/scripts/requirements_dev.txt /tmp/requirements_dev.txt
RUN python3 -m venv --system-site-packages /opt/venv \
&& . /opt/venv/bin/activate \
&& pip install --no-cache-dir --require-hashes -r /tmp/requirements_dev.txt
# Füge den venv-Pfad zur globalen PATH-Variable hinzu, damit die Tools verfügbar sind
ENV PATH="/opt/venv/bin:$PATH"
COPY . /workspace
RUN mkdir -p /tmp/stirling-pdf \
&& fc-cache -f -v \
&& adduser --disabled-password --gecos '' devuser \
&& chown -R devuser:devuser /home/devuser /workspace /tmp/stirling-pdf
RUN echo "devuser ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/devuser \
&& chmod 0440 /etc/sudoers.d/devuser
# Setze das Arbeitsverzeichnis (wird später per Bind-Mount überschrieben)
WORKDIR /workspace
RUN chmod +x /workspace/.devcontainer/git-init.sh /workspace/.devcontainer/init-setup.sh
# Wechsel zum NichtRoot Benutzer
USER devuser
@@ -1,4 +1,3 @@
# Backend fat Dockerfile - Java Spring Boot with all dependencies and build stage
# Build the application
FROM gradle:8.14-jdk21 AS build
@@ -53,6 +52,7 @@ ENV DISABLE_ADDITIONAL_FEATURES=true \
TEMP=/tmp/stirling-pdf \
TMP=/tmp/stirling-pdf
# JDK for app
RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
echo "@community https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
@@ -76,37 +76,38 @@ RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/a
# pdftohtml
poppler-utils \
# OCR MY PDF (unpaper for descew and other advanced featues)
unpaper \
tesseract-ocr-data-eng \
tesseract-ocr-data-chi_sim \
tesseract-ocr-data-deu \
tesseract-ocr-data-fra \
tesseract-ocr-data-por \
ocrmypdf \
font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra font-liberation font-linux-libertine \
unpaper \
font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra font-liberation font-linux-libertine font-urw-base35 \
# CV
py3-opencv \
python3 \
ocrmypdf \
py3-pip \
py3-pillow@testing \
py3-pdf2image@testing && \
python3 -m venv /opt/venv && \
/opt/venv/bin/pip install --upgrade pip setuptools && \
/opt/venv/bin/pip install --no-cache-dir --upgrade pip setuptools && \
/opt/venv/bin/pip install --no-cache-dir --upgrade unoserver weasyprint && \
ln -s /usr/lib/libreoffice/program/uno.py /opt/venv/lib/python3.12/site-packages/ && \
ln -s /usr/lib/libreoffice/program/unohelper.py /opt/venv/lib/python3.12/site-packages/ && \
ln -s /usr/lib/libreoffice/program /opt/venv/lib/python3.12/site-packages/LibreOffice && \
mv /usr/share/tessdata /usr/share/tessdata-original && \
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /tmp/stirling-pdf /pipeline/watchedFolders /pipeline/finishedFolders && \
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /tmp/stirling-pdf && \
# Configure URW Base 35 fonts
ln -s /usr/share/fontconfig/conf.avail/69-urw-*.conf /etc/fonts/conf.d/ && \
fc-cache -f -v && \
chmod +x /scripts/* && \
chmod +x /scripts/init.sh && \
# User permissions
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /pipeline /usr/share/fonts/opentype/noto /configs /customFiles /pipeline /tmp/stirling-pdf && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline /tmp/stirling-pdf && \
chown stirlingpdfuser:stirlingpdfgroup /app.jar
EXPOSE 8080/tcp
# Set user and run command
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
CMD ["sh", "-c", "java -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/tmp/stirling-pdf -jar /app.jar & /opt/venv/bin/unoserver --port 2003 --interface 127.0.0.1"]
CMD ["sh", "-c", "java -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/tmp/stirling-pdf -jar /app.jar & /opt/venv/bin/unoserver --port 2003 --interface 127.0.0.1"]
@@ -1,28 +1,4 @@
# Backend ultra-lite Dockerfile - Java Spring Boot with minimal dependencies and build stage
# Build the application
FROM gradle:8.14-jdk21 AS build
COPY build.gradle .
COPY settings.gradle .
COPY gradlew .
COPY gradle gradle/
COPY app/core/build.gradle core/.
COPY app/common/build.gradle common/.
COPY app/proprietary/build.gradle proprietary/.
RUN ./gradlew build -x spotlessApply -x spotlessCheck -x test -x sonarqube || return 0
# Set the working directory
WORKDIR /app
# Copy the entire project to the working directory
COPY . .
# Build the application with DISABLE_ADDITIONAL_FEATURES=true
RUN DISABLE_ADDITIONAL_FEATURES=true \
STIRLING_PDF_DESKTOP_UI=false \
./gradlew clean build -x spotlessApply -x spotlessCheck -x test -x sonarqube
# Main stage
# use alpine
FROM alpine:3.22.1@sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1
ARG VERSION_TAG
@@ -42,9 +18,10 @@ ENV DISABLE_ADDITIONAL_FEATURES=true \
TMP=/tmp/stirling-pdf
# Copy necessary files
COPY scripts/download-security-jar.sh /scripts/download-security-jar.sh
COPY scripts/init-without-ocr.sh /scripts/init-without-ocr.sh
COPY scripts/installFonts.sh /scripts/installFonts.sh
COPY --from=build /app/app/core/build/libs/*.jar app.jar
COPY app/core/build/libs/*.jar app.jar
# Set up necessary directories and permissions
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
@@ -64,7 +41,7 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
mkdir -p /configs /logs /customFiles /usr/share/fonts/opentype/noto /tmp/stirling-pdf /pipeline/watchedFolders /pipeline/finishedFolders && \
chmod +x /scripts/*.sh && \
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /pipeline /configs /customFiles /pipeline /tmp/stirling-pdf && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /pipeline /configs /customFiles /tmp/stirling-pdf && \
chown stirlingpdfuser:stirlingpdfgroup /app.jar
# Set environment variables
+7 -7
View File
@@ -120,14 +120,14 @@ Stirling-PDF currently supports 40 languages!
| Azerbaijani (Azərbaycan Dili) (az_AZ) | ![62%](https://geps.dev/progress/62) |
| Basque (Euskara) (eu_ES) | ![36%](https://geps.dev/progress/36) |
| Bulgarian (Български) (bg_BG) | ![68%](https://geps.dev/progress/68) |
| Catalan (Català) (ca_CA) | ![68%](https://geps.dev/progress/68) |
| Catalan (Català) (ca_CA) | ![67%](https://geps.dev/progress/67) |
| Croatian (Hrvatski) (hr_HR) | ![60%](https://geps.dev/progress/60) |
| Czech (Česky) (cs_CZ) | ![70%](https://geps.dev/progress/70) |
| Danish (Dansk) (da_DK) | ![61%](https://geps.dev/progress/61) |
| Dutch (Nederlands) (nl_NL) | ![60%](https://geps.dev/progress/60) |
| English (English) (en_GB) | ![100%](https://geps.dev/progress/100) |
| English (US) (en_US) | ![100%](https://geps.dev/progress/100) |
| French (Français) (fr_FR) | ![89%](https://geps.dev/progress/89) |
| French (Français) (fr_FR) | ![88%](https://geps.dev/progress/88) |
| German (Deutsch) (de_DE) | ![98%](https://geps.dev/progress/98) |
| Greek (Ελληνικά) (el_GR) | ![67%](https://geps.dev/progress/67) |
| Hindi (हिंदी) (hi_IN) | ![67%](https://geps.dev/progress/67) |
@@ -135,12 +135,12 @@ Stirling-PDF currently supports 40 languages!
| Indonesian (Bahasa Indonesia) (id_ID) | ![62%](https://geps.dev/progress/62) |
| Irish (Gaeilge) (ga_IE) | ![68%](https://geps.dev/progress/68) |
| Italian (Italiano) (it_IT) | ![98%](https://geps.dev/progress/98) |
| Japanese (日本語) (ja_JP) | ![93%](https://geps.dev/progress/93) |
| Japanese (日本語) (ja_JP) | ![92%](https://geps.dev/progress/92) |
| Korean (한국어) (ko_KR) | ![67%](https://geps.dev/progress/67) |
| Norwegian (Norsk) (no_NB) | ![66%](https://geps.dev/progress/66) |
| Persian (فارسی) (fa_IR) | ![64%](https://geps.dev/progress/64) |
| Polish (Polski) (pl_PL) | ![72%](https://geps.dev/progress/72) |
| Portuguese (Português) (pt_PT) | ![69%](https://geps.dev/progress/69) |
| Portuguese (Português) (pt_PT) | ![68%](https://geps.dev/progress/68) |
| Portuguese Brazilian (Português) (pt_BR) | ![76%](https://geps.dev/progress/76) |
| Romanian (Română) (ro_RO) | ![57%](https://geps.dev/progress/57) |
| Russian (Русский) (ru_RU) | ![88%](https://geps.dev/progress/88) |
@@ -152,9 +152,9 @@ Stirling-PDF currently supports 40 languages!
| Swedish (Svenska) (sv_SE) | ![65%](https://geps.dev/progress/65) |
| Thai (ไทย) (th_TH) | ![59%](https://geps.dev/progress/59) |
| Tibetan (བོད་ཡིག་) (bo_CN) | ![65%](https://geps.dev/progress/65) |
| Traditional Chinese (繁體中文) (zh_TW) | ![97%](https://geps.dev/progress/97) |
| Turkish (Türkçe) (tr_TR) | ![80%](https://geps.dev/progress/80) |
| Ukrainian (Українська) (uk_UA) | ![71%](https://geps.dev/progress/71) |
| Traditional Chinese (繁體中文) (zh_TW) | ![99%](https://geps.dev/progress/99) |
| Turkish (Türkçe) (tr_TR) | ![99%](https://geps.dev/progress/99) |
| Ukrainian (Українська) (uk_UA) | ![70%](https://geps.dev/progress/70) |
| Vietnamese (Tiếng Việt) (vi_VN) | ![57%](https://geps.dev/progress/57) |
| Malayalam (മലയാളം) (ml_IN) | ![73%](https://geps.dev/progress/73) |
+3 -3
View File
@@ -29,7 +29,7 @@ spotless {
dependencies {
api 'org.springframework.boot:spring-boot-starter-web'
api 'org.springframework.boot:spring-boot-starter-aop'
// api 'org.springframework.boot:spring-boot-starter-thymeleaf' // Deprecated - UI moved to React frontend
api 'org.springframework.boot:spring-boot-starter-thymeleaf'
api 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'
api 'com.fathzer:javaluator:3.0.6'
api 'com.posthog.java:posthog:1.2.0'
@@ -39,7 +39,7 @@ dependencies {
api "org.apache.pdfbox:pdfbox:$pdfboxVersion"
api 'jakarta.servlet:jakarta.servlet-api:6.1.0'
api 'org.snakeyaml:snakeyaml-engine:2.10'
api "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.9"
api 'jakarta.mail:jakarta.mail-api:2.1.3'
api "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.12"
api 'jakarta.mail:jakarta.mail-api:2.1.4'
runtimeOnly 'org.eclipse.angus:angus-mail:2.0.4'
}
@@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.FileOrUploadService;
import stirling.software.common.service.FileStorage;
import stirling.software.common.service.JobExecutorService;
@@ -34,7 +33,6 @@ public class AutoJobAspect {
private final JobExecutorService jobExecutorService;
private final HttpServletRequest request;
private final FileOrUploadService fileOrUploadService;
private final FileStorage fileStorage;
@Around("@annotation(autoJobPostMapping)")
@@ -53,7 +51,8 @@ public class AutoJobAspect {
boolean trackProgress = autoJobPostMapping.trackProgress();
log.debug(
"AutoJobPostMapping execution with async={}, timeout={}, retryCount={}, trackProgress={}",
"AutoJobPostMapping execution with async={}, timeout={}, retryCount={},"
+ " trackProgress={}",
async,
timeout > 0 ? timeout : "default",
retryCount,
@@ -148,7 +147,8 @@ public class AutoJobAspect {
} catch (Throwable ex) {
lastException = ex;
log.error(
"AutoJobAspect caught exception during job execution (attempt {}/{}): {}",
"AutoJobAspect caught exception during job execution (attempt"
+ " {}/{}): {}",
currentAttempt,
maxRetries,
ex.getMessage(),
@@ -11,6 +11,7 @@ import java.util.function.Predicate;
import java.util.stream.Stream;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
@@ -19,7 +20,9 @@ import org.springframework.context.annotation.Scope;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.ClassUtils;
import org.thymeleaf.spring6.SpringTemplateEngine;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@@ -57,7 +60,6 @@ public class AppConfig {
return v2Enabled;
}
/* Commented out Thymeleaf template engine bean - to be removed when frontend migration is complete
@Bean
@ConditionalOnProperty(name = "system.customHTMLFiles", havingValue = "true")
public SpringTemplateEngine templateEngine(ResourceLoader resourceLoader) {
@@ -65,7 +67,6 @@ public class AppConfig {
templateEngine.addTemplateResolver(new FileFallbackTemplateResolver(resourceLoader));
return templateEngine;
}
*/
@Bean(name = "loginEnabled")
public boolean loginEnabled() {
@@ -23,10 +23,30 @@ import stirling.software.common.util.YamlHelper;
@Slf4j
public class ConfigInitializer {
private static final int MIN_SETTINGS_FILE_LINES = 31;
public void ensureConfigExists() throws IOException, URISyntaxException {
// 1) If settings file doesn't exist, create from template
Path destPath = Paths.get(InstallationPathConfig.getSettingsPath());
if (Files.notExists(destPath)) {
boolean settingsFileExists = Files.exists(destPath);
long lineCount = settingsFileExists ? Files.readAllLines(destPath).size() : 0;
log.info("Current settings file line count: {}", lineCount);
if (!settingsFileExists || lineCount < MIN_SETTINGS_FILE_LINES) {
if (settingsFileExists) {
// move settings.yml to settings.yml.{timestamp}.bak
Path backupPath =
Paths.get(
InstallationPathConfig.getSettingsPath()
+ "."
+ System.currentTimeMillis()
+ ".bak");
Files.move(destPath, backupPath, StandardCopyOption.REPLACE_EXISTING);
log.info("Moved existing settings file to backup: {}", backupPath);
}
Files.createDirectories(destPath.getParent());
try (InputStream in =
getClass().getClassLoader().getResourceAsStream("settings.yml.template")) {
@@ -1,8 +1,19 @@
package stirling.software.common.configuration;
/* Commented out entire FileFallbackTemplateResolver class - Thymeleaf dependency removed
* This class will be removed when frontend migration to React is complete
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.thymeleaf.IEngineConfiguration;
import org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver;
import org.thymeleaf.templateresource.FileTemplateResource;
import org.thymeleaf.templateresource.ITemplateResource;
import lombok.extern.slf4j.Slf4j;
import stirling.software.common.model.InputStreamTemplateResource;
@Slf4j
public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateResolver {
@@ -46,4 +57,3 @@ public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateRe
return null;
}
}
*/
@@ -14,18 +14,22 @@ public class InstallationPathConfig {
private static final String CONFIG_PATH;
private static final String CUSTOM_FILES_PATH;
private static final String CLIENT_WEBUI_PATH;
private static final String SCRIPTS_PATH;
private static final String PIPELINE_PATH;
// Config paths
private static final String SETTINGS_PATH;
private static final String CUSTOM_SETTINGS_PATH;
private static final String SCRIPTS_PATH;
private static final String BACKUP_PATH;
// Backup paths
private static final String BACKUP_DB_PATH;
private static final String BACKUP_PRIVATE_KEY_PATH;
// Custom file paths
private static final String STATIC_PATH;
private static final String TEMPLATES_PATH;
private static final String SIGNATURES_PATH;
private static final String PRIVATE_KEY_PATH;
static {
BASE_PATH = initializeBasePath();
@@ -41,12 +45,16 @@ public class InstallationPathConfig {
SETTINGS_PATH = CONFIG_PATH + "settings.yml";
CUSTOM_SETTINGS_PATH = CONFIG_PATH + "custom_settings.yml";
SCRIPTS_PATH = CONFIG_PATH + "scripts" + File.separator;
BACKUP_PATH = CONFIG_PATH + "backup" + File.separator;
// Initialize backup paths
BACKUP_DB_PATH = BACKUP_PATH + "db" + File.separator;
BACKUP_PRIVATE_KEY_PATH = BACKUP_PATH + "keys" + File.separator;
// Initialize custom file paths
STATIC_PATH = CUSTOM_FILES_PATH + "static" + File.separator;
TEMPLATES_PATH = CUSTOM_FILES_PATH + "templates" + File.separator;
SIGNATURES_PATH = CUSTOM_FILES_PATH + "signatures" + File.separator;
PRIVATE_KEY_PATH = CONFIG_PATH + "db" + File.separator + "keys" + File.separator;
}
private static String initializeBasePath() {
@@ -124,6 +132,10 @@ public class InstallationPathConfig {
}
public static String getPrivateKeyPath() {
return PRIVATE_KEY_PATH;
return BACKUP_PRIVATE_KEY_PATH;
}
public static String getBackupPath() {
return BACKUP_DB_PATH;
}
}
@@ -41,6 +41,7 @@ import stirling.software.common.model.oauth2.GitHubProvider;
import stirling.software.common.model.oauth2.GoogleProvider;
import stirling.software.common.model.oauth2.KeycloakProvider;
import stirling.software.common.model.oauth2.Provider;
import stirling.software.common.service.SsrfProtectionService.SsrfProtectionLevel;
import stirling.software.common.util.ValidationUtils;
@Data
@@ -328,12 +329,18 @@ public class ApplicationProperties {
private CustomPaths customPaths = new CustomPaths();
private String fileUploadLimit;
private TempFileManagement tempFileManagement = new TempFileManagement();
private DatabaseBackup databaseBackup = new DatabaseBackup();
public boolean isAnalyticsEnabled() {
return this.getEnableAnalytics() != null && this.getEnableAnalytics();
}
}
@Data
public static class DatabaseBackup {
private String cron = "0 0 0 * * ?"; // daily at midnight
}
@Data
public static class CustomPaths {
private Pipeline pipeline = new Pipeline();
@@ -372,8 +379,7 @@ public class ApplicationProperties {
public String getBaseTmpDir() {
return baseTmpDir != null && !baseTmpDir.isEmpty()
? baseTmpDir
: java.lang.System.getProperty("java.io.tmpdir").replaceAll("/+$", "")
+ "/stirling-pdf";
: java.lang.System.getProperty("java.io.tmpdir") + "/stirling-pdf";
}
@JsonIgnore
@@ -391,7 +397,7 @@ public class ApplicationProperties {
@Data
public static class UrlSecurity {
private boolean enabled = true;
private String level = "MEDIUM"; // MAX, MEDIUM, OFF
private SsrfProtectionLevel level = SsrfProtectionLevel.MEDIUM; // MAX, MEDIUM, OFF
private List<String> allowedDomains = new ArrayList<>();
private List<String> blockedDomains = new ArrayList<>();
private List<String> internalTlds =
@@ -8,9 +8,11 @@ import java.util.Locale;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FileInfo {
private static final DateTimeFormatter DATE_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@@ -1,17 +1,20 @@
package stirling.software.common.model;
/* Commented out entire InputStreamTemplateResource class - Thymeleaf dependency removed
* This class will be removed when frontend migration to React is complete
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import org.thymeleaf.templateresource.ITemplateResource;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public class InputStreamTemplateResource implements ITemplateResource {
private InputStream inputStream;
private String characterEncoding;
public InputStreamTemplateResource(InputStream inputStream, String characterEncoding) {
this.inputStream = inputStream;
this.characterEncoding = characterEncoding;
}
private final InputStream inputStream;
private final String characterEncoding;
@Override
public Reader reader() throws IOException {
@@ -39,4 +42,3 @@ public class InputStreamTemplateResource implements ITemplateResource {
return inputStream != null;
}
}
*/
@@ -2,11 +2,15 @@ package stirling.software.common.model;
import java.util.Calendar;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PdfMetadata {
private String author;
private String producer;
@@ -252,8 +252,10 @@ public class JobExecutorService {
}
}
if (response.getHeaders().getContentType() != null) {
contentType = response.getHeaders().getContentType().toString();
MediaType mediaType = response.getHeaders().getContentType();
if (mediaType != null) {
contentType = mediaType.toString();
}
// Store byte array directly to disk
@@ -1,5 +1,7 @@
package stirling.software.common.service;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
@@ -51,21 +53,17 @@ public class SsrfProtectionService {
SsrfProtectionLevel level = parseProtectionLevel(config.getLevel());
switch (level) {
case OFF:
return true;
case MAX:
return isMaxSecurityAllowed(trimmedUrl, config);
case MEDIUM:
return isMediumSecurityAllowed(trimmedUrl, config);
default:
return false;
}
return switch (level) {
case OFF -> true;
case MAX -> isMaxSecurityAllowed(trimmedUrl, config);
case MEDIUM -> isMediumSecurityAllowed(trimmedUrl, config);
default -> false;
};
}
private SsrfProtectionLevel parseProtectionLevel(String level) {
private SsrfProtectionLevel parseProtectionLevel(SsrfProtectionLevel level) {
try {
return SsrfProtectionLevel.valueOf(level.toUpperCase());
return SsrfProtectionLevel.valueOf(level.name());
} catch (IllegalArgumentException e) {
log.warn("Invalid SSRF protection level '{}', defaulting to MEDIUM", level);
return SsrfProtectionLevel.MEDIUM;
@@ -172,15 +170,62 @@ public class SsrfProtectionService {
}
private boolean isPrivateAddress(InetAddress address) {
return address.isSiteLocalAddress()
|| address.isAnyLocalAddress()
|| isPrivateIPv4Range(address.getHostAddress());
if (address.isAnyLocalAddress() || address.isLoopbackAddress()) {
return true;
}
if (address instanceof Inet4Address) {
return isPrivateIPv4Range(address.getHostAddress());
}
if (address instanceof Inet6Address addr6) {
if (addr6.isLinkLocalAddress() || addr6.isSiteLocalAddress()) {
return true;
}
byte[] bytes = addr6.getAddress();
if (isIpv4MappedAddress(bytes)) {
String ipv4 =
(bytes[12] & 0xff)
+ "."
+ (bytes[13] & 0xff)
+ "."
+ (bytes[14] & 0xff)
+ "."
+ (bytes[15] & 0xff);
return isPrivateIPv4Range(ipv4);
}
int firstByte = bytes[0] & 0xff;
// Check for IPv6 unique local addresses (fc00::/7)
if ((firstByte & 0xfe) == 0xfc) {
return true;
}
}
return false;
}
private boolean isIpv4MappedAddress(byte[] addr) {
if (addr.length != 16) {
return false;
}
for (int i = 0; i < 10; i++) {
if (addr[i] != 0) {
return false;
}
}
// For IPv4-mapped IPv6 addresses, bytes 10 and 11 must be 0xff (i.e., address is
// ::ffff:w.x.y.z)
return addr[10] == (byte) 0xff && addr[11] == (byte) 0xff;
}
private boolean isPrivateIPv4Range(String ip) {
// Includes RFC1918, loopback, link-local, and unspecified addresses
return ip.startsWith("10.")
|| ip.startsWith("192.168.")
|| (ip.startsWith("172.") && isInRange172(ip))
|| ip.startsWith("169.254.")
|| ip.startsWith("127.")
|| "0.0.0.0".equals(ip);
}
@@ -192,17 +237,31 @@ public class SsrfProtectionService {
int secondOctet = Integer.parseInt(parts[1]);
return secondOctet >= 16 && secondOctet <= 31;
} catch (NumberFormatException e) {
return false;
}
}
return false;
}
private boolean isCloudMetadataAddress(String ip) {
String normalizedIp = normalizeIpv4MappedAddress(ip);
// Cloud metadata endpoints for AWS, GCP, Azure, Oracle Cloud, and IBM Cloud
return ip.startsWith("169.254.169.254") // AWS/GCP/Azure
|| ip.startsWith("fd00:ec2::254") // AWS IPv6
|| ip.startsWith("169.254.169.253") // Oracle Cloud
|| ip.startsWith("169.254.169.250"); // IBM Cloud
return normalizedIp.startsWith("169.254.169.254") // AWS/GCP/Azure
|| normalizedIp.startsWith("fd00:ec2::254") // AWS IPv6
|| normalizedIp.startsWith("169.254.169.253") // Oracle Cloud
|| normalizedIp.startsWith("169.254.169.250"); // IBM Cloud
}
private String normalizeIpv4MappedAddress(String ip) {
if (ip == null) {
return "";
}
if (ip.startsWith("::ffff:")) {
return ip.substring(7);
}
int lastColon = ip.lastIndexOf(':');
if (lastColon >= 0 && ip.indexOf('.') > lastColon) {
return ip.substring(lastColon + 1);
}
return ip;
}
}
@@ -0,0 +1,301 @@
package stirling.software.common.util;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.zip.Adler32;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
import lombok.experimental.UtilityClass;
@UtilityClass
public class ChecksumUtils {
/** Shared buffer size for streaming I/O. */
private static final int BUFFER_SIZE = 8192;
/** Mask to extract the lower 32 bits of a long value (unsigned int). */
private static final long UNSIGNED_32_BIT_MASK = 0xFFFFFFFFL;
/**
* Computes a checksum for the given file using the chosen algorithm and returns a lowercase hex
* string.
*
* <p>For digest algorithms (e.g., SHA-256, SHA-1, MD5), this returns the digest as hex. For
* 32-bit {@link Checksum} algorithms ("CRC32", "ADLER32"), this returns an 8-character
* lowercase hex string of the unsigned 32-bit value.
*
* @param path file to read
* @param algorithm algorithm name (case-insensitive). Special values: "CRC32", "ADLER32".
* @return hex string of the checksum
* @throws IOException if the file cannot be read
*/
public static String checksum(Path path, String algorithm) throws IOException {
try (InputStream is = Files.newInputStream(path)) {
return checksum(is, algorithm);
}
}
/**
* Computes a checksum for the given stream using the chosen algorithm and returns a lowercase
* hex string.
*
* <p><strong>Note:</strong> This method does <em>not</em> close the provided stream.
*
* @param is input stream (not closed by this method)
* @param algorithm algorithm name (case-insensitive). Special values: "CRC32", "ADLER32".
* @return hex string of the checksum
* @throws IOException if reading from the stream fails
*/
public static String checksum(InputStream is, String algorithm) throws IOException {
switch (algorithm.toUpperCase(Locale.ROOT)) {
case "CRC32":
return checksumChecksum(is, new CRC32());
case "ADLER32":
return checksumChecksum(is, new Adler32());
default:
return toHex(checksumBytes(is, algorithm));
}
}
/**
* Computes a checksum for the given file using the chosen algorithm and returns a Base64
* encoded string.
*
* <p>For digest algorithms this is the Base64 of the raw digest bytes. For 32-bit checksum
* algorithms ("CRC32", "ADLER32"), this is the Base64 of the 4-byte big-endian unsigned value.
*
* @param path file to read
* @param algorithm algorithm name (case-insensitive). Special values: "CRC32", "ADLER32".
* @return Base64-encoded checksum bytes
* @throws IOException if the file cannot be read
*/
public static String checksumBase64(Path path, String algorithm) throws IOException {
try (InputStream is = Files.newInputStream(path)) {
return checksumBase64(is, algorithm);
}
}
/**
* Computes a checksum for the given stream using the chosen algorithm and returns a Base64
* encoded string.
*
* <p><strong>Note:</strong> This method does <em>not</em> close the provided stream.
*
* @param is input stream (not closed by this method)
* @param algorithm algorithm name (case-insensitive). Special values: "CRC32", "ADLER32".
* @return Base64-encoded checksum bytes
* @throws IOException if reading from the stream fails
*/
public static String checksumBase64(InputStream is, String algorithm) throws IOException {
switch (algorithm.toUpperCase(Locale.ROOT)) {
case "CRC32":
return Base64.getEncoder().encodeToString(checksumChecksumBytes(is, new CRC32()));
case "ADLER32":
return Base64.getEncoder().encodeToString(checksumChecksumBytes(is, new Adler32()));
default:
return Base64.getEncoder().encodeToString(checksumBytes(is, algorithm));
}
}
/**
* Computes multiple checksums for the given file in a single pass over the data.
*
* <p>Returns a map from algorithm name to lowercase hex string. Order of results follows the
* order of the provided {@code algorithms}.
*
* @param path file to read
* @param algorithms algorithm names (case-insensitive). Special: "CRC32", "ADLER32".
* @return map of algorithm → hex string
* @throws IOException if the file cannot be read
*/
public static Map<String, String> checksums(Path path, String... algorithms)
throws IOException {
try (InputStream is = Files.newInputStream(path)) {
return checksums(is, algorithms);
}
}
/**
* Computes multiple checksums for the given stream in a single pass over the data.
*
* <p><strong>Note:</strong> This method does <em>not</em> close the provided stream.
*
* @param is input stream (not closed by this method)
* @param algorithms algorithm names (case-insensitive). Special: "CRC32", "ADLER32".
* @return map of algorithm → hex string
* @throws IOException if reading from the stream fails
*/
public static Map<String, String> checksums(InputStream is, String... algorithms)
throws IOException {
// Use LinkedHashMap to preserve the order of requested algorithms in the result.
Map<String, MessageDigest> digests = new LinkedHashMap<>();
Map<String, Checksum> checksums = new LinkedHashMap<>();
for (String algorithm : algorithms) {
String key = algorithm; // keep original key for output
switch (algorithm.toUpperCase(Locale.ROOT)) {
case "CRC32":
checksums.put(key, new CRC32());
break;
case "ADLER32":
checksums.put(key, new Adler32());
break;
default:
try {
// For MessageDigest, pass the original name (case-insensitive per JCA)
digests.put(key, MessageDigest.getInstance(algorithm));
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("Unsupported algorithm: " + algorithm, e);
}
}
}
byte[] buffer = new byte[BUFFER_SIZE];
int read;
while ((read = is.read(buffer)) != -1) {
for (MessageDigest digest : digests.values()) {
digest.update(buffer, 0, read);
}
for (Checksum cs : checksums.values()) {
cs.update(buffer, 0, read);
}
}
Map<String, String> results = new LinkedHashMap<>();
for (Map.Entry<String, MessageDigest> entry : digests.entrySet()) {
results.put(entry.getKey(), toHex(entry.getValue().digest()));
}
for (Map.Entry<String, Checksum> entry : checksums.entrySet()) {
// Keep value as long and mask to ensure unsigned hex formatting.
long unsigned32 = entry.getValue().getValue() & UNSIGNED_32_BIT_MASK;
results.put(entry.getKey(), String.format("%08x", unsigned32));
}
return results;
}
/**
* Compares the checksum of a file with an expected hex string (case-insensitive).
*
* @param path file to read
* @param algorithm algorithm name (case-insensitive). Special: "CRC32", "ADLER32".
* @param expected expected hex string (case-insensitive)
* @return {@code true} if they match, otherwise {@code false}
* @throws IOException if the file cannot be read
*/
public static boolean matches(Path path, String algorithm, String expected) throws IOException {
try (InputStream is = Files.newInputStream(path)) {
return matches(is, algorithm, expected);
}
}
/**
* Compares the checksum of a stream with an expected hex string (case-insensitive).
*
* <p><strong>Note:</strong> This method does <em>not</em> close the provided stream.
*
* @param is input stream (not closed by this method)
* @param algorithm algorithm name (case-insensitive). Special: "CRC32", "ADLER32".
* @param expected expected hex string (case-insensitive)
* @return {@code true} if they match, otherwise {@code false}
* @throws IOException if reading from the stream fails
*/
public static boolean matches(InputStream is, String algorithm, String expected)
throws IOException {
return checksum(is, algorithm).equalsIgnoreCase(expected);
}
// ---------- Internal helpers ----------
/**
* Computes a MessageDigest over a stream and returns the raw digest bytes.
*
* @param is input stream (not closed)
* @param algorithm JCA MessageDigest algorithm (e.g., "SHA-256")
* @return raw digest bytes
* @throws IOException if reading fails
* @throws IllegalStateException if the algorithm is unsupported
*/
private static byte[] checksumBytes(InputStream is, String algorithm) throws IOException {
try {
MessageDigest digest = MessageDigest.getInstance(algorithm);
byte[] buffer = new byte[BUFFER_SIZE];
int read;
while ((read = is.read(buffer)) != -1) {
digest.update(buffer, 0, read);
}
return digest.digest();
} catch (NoSuchAlgorithmException e) {
// Keep the message explicit to aid debugging
throw new IllegalStateException("Unsupported algorithm: " + algorithm, e);
}
}
/**
* Computes a 32-bit {@link Checksum} over a stream and returns the lowercase 8-char hex of the
* unsigned 32-bit value.
*
* @param is input stream (not closed)
* @param checksum checksum implementation (CRC32, Adler32, etc.)
* @return 8-character lowercase hex (big-endian representation)
* @throws IOException if reading fails
*/
private static String checksumChecksum(InputStream is, Checksum checksum) throws IOException {
byte[] buffer = new byte[BUFFER_SIZE];
int read;
while ((read = is.read(buffer)) != -1) {
checksum.update(buffer, 0, read);
}
// Keep as long and mask to ensure correct unsigned representation.
long unsigned32 = checksum.getValue() & UNSIGNED_32_BIT_MASK;
return String.format("%08x", unsigned32);
}
/**
* Computes a 32-bit {@link Checksum} over a stream and returns the raw 4-byte big-endian
* representation of the unsigned 32-bit value.
*
* <p>Cast to int already truncates to the lower 32 bits; the sign is irrelevant because we
* serialize the bit pattern directly into 4 bytes.
*
* @param is input stream (not closed)
* @param checksum checksum implementation (CRC32, Adler32, etc.)
* @return 4 bytes (big-endian)
* @throws IOException if reading fails
*/
private static byte[] checksumChecksumBytes(InputStream is, Checksum checksum)
throws IOException {
byte[] buffer = new byte[BUFFER_SIZE];
int read;
while ((read = is.read(buffer)) != -1) {
checksum.update(buffer, 0, read);
}
// Cast keeps only the lower 32 bits; mask is unnecessary here.
int v = (int) checksum.getValue();
return ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(v).array();
}
/**
* Converts bytes to a lowercase hex string.
*
* @param hash the byte array to convert
* @return the lowercase hex string
*/
private static String toHex(byte[] hash) {
StringBuilder sb = new StringBuilder(hash.length * 2);
for (byte b : hash) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}
@@ -4,7 +4,6 @@ import org.owasp.html.AttributePolicy;
import org.owasp.html.HtmlPolicyBuilder;
import org.owasp.html.PolicyFactory;
import org.owasp.html.Sanitizers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import stirling.software.common.model.ApplicationProperties;
@@ -16,7 +15,6 @@ public class CustomHtmlSanitizer {
private final SsrfProtectionService ssrfProtectionService;
private final ApplicationProperties applicationProperties;
@Autowired
public CustomHtmlSanitizer(
SsrfProtectionService ssrfProtectionService,
ApplicationProperties applicationProperties) {
@@ -142,7 +142,8 @@ public class PdfUtils {
ImageType colorType,
boolean singleImage,
int DPI,
String filename)
String filename,
boolean includeAnnotations)
throws IOException, Exception {
// Validate and limit DPI to prevent excessive memory usage
@@ -163,6 +164,9 @@ public class PdfUtils {
try (PDDocument document = pdfDocumentFactory.load(inputStream)) {
PDFRenderer pdfRenderer = new PDFRenderer(document);
pdfRenderer.setSubsamplingAllowed(true);
if (!includeAnnotations) {
pdfRenderer.setAnnotationsFilter(annotation -> false);
}
int pageCount = document.getNumberOfPages();
// Create a ByteArrayOutputStream to save the image(s) to
@@ -15,6 +15,8 @@ import java.util.concurrent.TimeUnit;
import io.github.pixee.security.BoundedLineReader;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import stirling.software.common.model.ApplicationProperties;
@@ -303,6 +305,8 @@ public class ProcessExecutor {
OCR_MY_PDF
}
@Setter
@Getter
public class ProcessExecutorResult {
int rc;
String messages;
@@ -312,20 +316,5 @@ public class ProcessExecutor {
this.messages = messages;
}
public int getRc() {
return rc;
}
public void setRc(int rc) {
this.rc = rc;
}
public String getMessages() {
return messages;
}
public void setMessages(String messages) {
this.messages = messages;
}
}
}
@@ -4,6 +4,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
/**
@@ -14,6 +15,7 @@ import lombok.extern.slf4j.Slf4j;
public class TempFile implements AutoCloseable {
private final TempFileManager manager;
@Getter
private final File file;
public TempFile(TempFileManager manager, String suffix) throws IOException {
@@ -21,10 +23,6 @@ public class TempFile implements AutoCloseable {
this.file = manager.createTempFile(suffix);
}
public File getFile() {
return file;
}
public Path getPath() {
return file.toPath();
}
@@ -11,6 +11,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import lombok.Getter;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@@ -24,8 +25,22 @@ import lombok.extern.slf4j.Slf4j;
public class TempFileRegistry {
private final ConcurrentMap<Path, Instant> registeredFiles = new ConcurrentHashMap<>();
/**
* -- GETTER --
* Get all registered third-party temporary files.
*
* @return Set of third-party file paths
*/
@Getter
private final Set<Path> thirdPartyTempFiles =
Collections.newSetFromMap(new ConcurrentHashMap<>());
/**
* -- GETTER --
* Get all registered temporary directories.
*
* @return Set of temporary directory paths
*/
@Getter
private final Set<Path> tempDirectories = Collections.newSetFromMap(new ConcurrentHashMap<>());
/**
@@ -133,24 +148,6 @@ public class TempFileRegistry {
.collect(Collectors.toSet());
}
/**
* Get all registered third-party temporary files.
*
* @return Set of third-party file paths
*/
public Set<Path> getThirdPartyTempFiles() {
return thirdPartyTempFiles;
}
/**
* Get all registered temporary directories.
*
* @return Set of temporary directory paths
*/
public Set<Path> getTempDirectories() {
return tempDirectories;
}
/**
* Check if a file is registered in the registry.
*
@@ -29,7 +29,6 @@ import jakarta.servlet.http.HttpServletRequest;
import stirling.software.common.aop.AutoJobAspect;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.FileOrUploadService;
import stirling.software.common.service.FileStorage;
import stirling.software.common.service.JobExecutorService;
import stirling.software.common.service.JobQueue;
@@ -44,8 +43,6 @@ class AutoJobPostMappingIntegrationTest {
@Mock private HttpServletRequest request;
@Mock private FileOrUploadService fileOrUploadService;
@Mock private FileStorage fileStorage;
@Mock private ResourceMonitor resourceMonitor;
@@ -54,8 +51,7 @@ class AutoJobPostMappingIntegrationTest {
@BeforeEach
void setUp() {
autoJobAspect =
new AutoJobAspect(jobExecutorService, request, fileOrUploadService, fileStorage);
autoJobAspect = new AutoJobAspect(jobExecutorService, request, fileStorage);
}
@Mock private ProceedingJoinPoint joinPoint;
@@ -179,7 +179,7 @@ class ApplicationPropertiesLogicTest {
assertEquals(30, t.getOcrMyPdfTimeoutMinutes());
}
@Deprecated
@Deprecated(since = "0.45.0")
@Test
void enterprise_metadata_defaults() {
ApplicationProperties.EnterpriseEdition ee = new ApplicationProperties.EnterpriseEdition();
@@ -0,0 +1,111 @@
package stirling.software.common.model;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.File;
import java.time.LocalDateTime;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
public class FileInfoTest {
@ParameterizedTest(name = "{index}: fileSize={0}")
@CsvSource({
"0, '0 Bytes'",
"1023, '1023 Bytes'",
"1024, '1.00 KB'",
"1048575, '1024.00 KB'", // Do we really want this as result?
"1048576, '1.00 MB'",
"1073741823, '1024.00 MB'", // Do we really want this as result?
"1073741824, '1.00 GB'"
})
void testGetFormattedFileSize(long fileSize, String expectedFormattedSize) {
FileInfo fileInfo =
new FileInfo(
"example.txt",
File.separator
+ "path"
+ File.separator
+ "to"
+ File.separator
+ "example.txt",
LocalDateTime.now(),
fileSize,
LocalDateTime.now().minusDays(1));
assertEquals(expectedFormattedSize, fileInfo.getFormattedFileSize());
}
@Test
void testGetFilePathAsPath() {
FileInfo fileInfo =
new FileInfo(
"test.pdf",
File.separator + "tmp" + File.separator + "test.pdf",
LocalDateTime.now(),
1234,
LocalDateTime.now().minusDays(2));
assertEquals(
File.separator + "tmp" + File.separator + "test.pdf",
fileInfo.getFilePathAsPath().toString());
}
@Test
void testGetFormattedModificationDate() {
LocalDateTime modDate = LocalDateTime.of(2024, 6, 1, 15, 30, 45);
FileInfo fileInfo =
new FileInfo(
"file.txt",
File.separator + "file.txt",
modDate,
100,
LocalDateTime.of(2024, 5, 31, 10, 0, 0));
assertEquals("2024-06-01 15:30:45", fileInfo.getFormattedModificationDate());
}
@Test
void testGetFormattedCreationDate() {
LocalDateTime creationDate = LocalDateTime.of(2023, 12, 25, 8, 15, 0);
FileInfo fileInfo =
new FileInfo(
"holiday.txt",
File.separator + "holiday.txt",
LocalDateTime.of(2024, 1, 1, 0, 0, 0),
500,
creationDate);
assertEquals("2023-12-25 08:15:00", fileInfo.getFormattedCreationDate());
}
@Test
void testGettersAndSetters() {
LocalDateTime now = LocalDateTime.now();
FileInfo fileInfo =
new FileInfo(
"doc.pdf",
File.separator + "docs" + File.separator + "doc.pdf",
now,
2048,
now.minusDays(1));
// Test getters
assertEquals("doc.pdf", fileInfo.getFileName());
assertEquals(File.separator + "docs" + File.separator + "doc.pdf", fileInfo.getFilePath());
assertEquals(now, fileInfo.getModificationDate());
assertEquals(2048, fileInfo.getFileSize());
assertEquals(now.minusDays(1), fileInfo.getCreationDate());
// Test setters
fileInfo.setFileName("new.pdf");
fileInfo.setFilePath(File.separator + "new" + File.separator + "new.pdf");
fileInfo.setModificationDate(now.plusDays(1));
fileInfo.setFileSize(4096);
fileInfo.setCreationDate(now.minusDays(2));
assertEquals("new.pdf", fileInfo.getFileName());
assertEquals(File.separator + "new" + File.separator + "new.pdf", fileInfo.getFilePath());
assertEquals(now.plusDays(1), fileInfo.getModificationDate());
assertEquals(4096, fileInfo.getFileSize());
assertEquals(now.minusDays(2), fileInfo.getCreationDate());
}
}
@@ -0,0 +1,94 @@
package stirling.software.common.model;
import static org.junit.jupiter.api.Assertions.*;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
public class InputStreamTemplateResourceTest {
@Test
void gettersReturnProvidedFields() {
byte[] data = {1, 2, 3};
InputStream is = new ByteArrayInputStream(data);
String encoding = "UTF-8";
InputStreamTemplateResource resource = new InputStreamTemplateResource(is, encoding);
assertSame(is, resource.getInputStream());
assertEquals(encoding, resource.getCharacterEncoding());
}
@Test
void fieldsAreFinal() throws NoSuchFieldException {
Field inputStreamField = InputStreamTemplateResource.class.getDeclaredField("inputStream");
Field characterEncodingField =
InputStreamTemplateResource.class.getDeclaredField("characterEncoding");
assertTrue(Modifier.isFinal(inputStreamField.getModifiers()));
assertTrue(Modifier.isFinal(characterEncodingField.getModifiers()));
}
@Test
void noSetterMethodsPresent() {
long setterCount =
Arrays.stream(InputStreamTemplateResource.class.getDeclaredMethods())
.filter(method -> method.getName().startsWith("set"))
.count();
assertEquals(0, setterCount, "InputStreamTemplateResource should not have setter methods");
}
@Test
void readerReturnsCorrectContent() throws Exception {
String content = "Hello, world!";
InputStream is = new ByteArrayInputStream(content.getBytes("UTF-8"));
InputStreamTemplateResource resource = new InputStreamTemplateResource(is, "UTF-8");
try (Reader reader = resource.reader()) {
char[] buffer = new char[content.length()];
int read = reader.read(buffer);
assertEquals(content.length(), read);
assertEquals(content, new String(buffer));
}
}
@Test
void relativeThrowsUnsupportedOperationException() {
InputStream is = new ByteArrayInputStream(new byte[0]);
InputStreamTemplateResource resource = new InputStreamTemplateResource(is, "UTF-8");
assertThrows(UnsupportedOperationException.class, () -> resource.relative("other"));
}
@Test
void getDescriptionReturnsExpectedString() {
InputStream is = new ByteArrayInputStream(new byte[0]);
InputStreamTemplateResource resource = new InputStreamTemplateResource(is, "UTF-8");
assertEquals("InputStream resource [Stream]", resource.getDescription());
}
@Test
void getBaseNameReturnsExpectedString() {
InputStream is = new ByteArrayInputStream(new byte[0]);
InputStreamTemplateResource resource = new InputStreamTemplateResource(is, "UTF-8");
assertEquals("streamResource", resource.getBaseName());
}
@Test
void existsReturnsTrueWhenInputStreamNotNull() {
InputStream is = new ByteArrayInputStream(new byte[0]);
InputStreamTemplateResource resource = new InputStreamTemplateResource(is, "UTF-8");
assertTrue(resource.exists());
}
@Test
void existsReturnsFalseWhenInputStreamIsNull() {
InputStreamTemplateResource resource = new InputStreamTemplateResource(null, "UTF-8");
assertFalse(resource.exists());
}
}
@@ -0,0 +1,66 @@
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import org.junit.jupiter.api.Test;
public class ChecksumUtilsTest {
@Test
void computeChecksums_basic() throws Exception {
byte[] data = "hello".getBytes(StandardCharsets.UTF_8);
// MD5 (hex)
try (InputStream is = new ByteArrayInputStream(data)) {
assertEquals("5d41402abc4b2a76b9719d911017c592", ChecksumUtils.checksum(is, "MD5"));
}
// MD5 (Base64)
try (InputStream is = new ByteArrayInputStream(data)) {
assertEquals("XUFAKrxLKna5cZ2REBfFkg==", ChecksumUtils.checksumBase64(is, "MD5"));
}
// MD5 + CRC32 (hex map)
try (InputStream is = new ByteArrayInputStream(data)) {
Map<String, String> map = ChecksumUtils.checksums(is, "MD5", "CRC32");
assertEquals("5d41402abc4b2a76b9719d911017c592", map.get("MD5"));
assertEquals("3610a686", map.get("CRC32"));
}
}
@Test
void crc32_base64_bigEndianBytes_forHello() throws Exception {
// CRC32("hello") = 0x3610A686 → bytes: 36 10 A6 86 → Base64: "NhCmhg=="
byte[] data = "hello".getBytes(StandardCharsets.UTF_8);
try (InputStream is = new ByteArrayInputStream(data)) {
assertEquals("NhCmhg==", ChecksumUtils.checksumBase64(is, "CRC32"));
}
}
@Test
void crc32_unsignedFormatting_highBitSet() throws Exception {
// CRC32 of single zero byte (0x00) is 0xD202EF8D (>= 0x8000_0000)
byte[] data = new byte[] {0x00};
// Hex (unsigned, 8 chars, lowercase)
try (InputStream is = new ByteArrayInputStream(data)) {
assertEquals("d202ef8d", ChecksumUtils.checksum(is, "CRC32"));
}
// Base64 of the 4-byte big-endian representation
try (InputStream is = new ByteArrayInputStream(data)) {
assertEquals("0gLvjQ==", ChecksumUtils.checksumBase64(is, "CRC32"));
}
// matches(..) must be case-insensitive for hex
try (InputStream is = new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8))) {
assertTrue(ChecksumUtils.matches(is, "CRC32", "3610A686")); // uppercase expected
}
}
}
@@ -586,7 +586,10 @@ class EmlToPdfTest {
when(mockPdDocument.getNumberOfPages()).thenReturn(1);
try (MockedStatic<FileToPdf> fileToPdf =
mockStatic(FileToPdf.class, org.mockito.Mockito.withSettings().lenient())) {
mockStatic(
FileToPdf.class,
org.mockito.Mockito.withSettings()
.defaultAnswer(org.mockito.Answers.RETURNS_DEFAULTS))) {
fileToPdf
.when(
() ->
@@ -657,7 +660,10 @@ class EmlToPdfTest {
when(mockPdDocument.getNumberOfPages()).thenReturn(1);
try (MockedStatic<FileToPdf> fileToPdf =
mockStatic(FileToPdf.class, org.mockito.Mockito.withSettings().lenient())) {
mockStatic(
FileToPdf.class,
org.mockito.Mockito.withSettings()
.defaultAnswer(org.mockito.Answers.RETURNS_DEFAULTS))) {
fileToPdf
.when(
() ->
@@ -724,7 +730,10 @@ class EmlToPdfTest {
String errorMessage = "Conversion failed";
try (MockedStatic<FileToPdf> fileToPdf =
mockStatic(FileToPdf.class, org.mockito.Mockito.withSettings().lenient())) {
mockStatic(
FileToPdf.class,
org.mockito.Mockito.withSettings()
.defaultAnswer(org.mockito.Answers.RETURNS_DEFAULTS))) {
fileToPdf
.when(
() ->
@@ -1,35 +0,0 @@
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.time.LocalDateTime;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import stirling.software.common.model.FileInfo;
public class FileInfoTest {
@ParameterizedTest(name = "{index}: fileSize={0}")
@CsvSource({
"0, '0 Bytes'",
"1023, '1023 Bytes'",
"1024, '1.00 KB'",
"1048575, '1024.00 KB'", // Do we really want this as result?
"1048576, '1.00 MB'",
"1073741823, '1024.00 MB'", // Do we really want this as result?
"1073741824, '1.00 GB'"
})
void testGetFormattedFileSize(long fileSize, String expectedFormattedSize) {
FileInfo fileInfo =
new FileInfo(
"example.txt",
"/path/to/example.txt",
LocalDateTime.now(),
fileSize,
LocalDateTime.now().minusDays(1));
assertEquals(expectedFormattedSize, fileInfo.getFormattedFileSize());
}
}
+4
View File
@@ -170,6 +170,10 @@ out/
*.jks
*.asc
# test-cert
!**/test/resources/certs/test-cert.*
!**/test/resources/certs/test-key.*
# SSH Keys
*.pub
*.priv
+1 -6
View File
@@ -58,7 +58,7 @@ dependencies {
implementation 'commons-io:commons-io:2.20.0'
implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion"
implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion"
implementation 'io.micrometer:micrometer-core:1.15.2'
implementation 'io.micrometer:micrometer-core:1.15.3'
implementation 'com.google.zxing:core:3.5.3'
implementation "org.commonmark:commonmark:$commonmarkVersion" // https://mvnrepository.com/artifact/org.commonmark/commonmark
implementation "org.commonmark:commonmark-ext-gfm-tables:$commonmarkVersion"
@@ -114,11 +114,6 @@ sourceSets {
}
test {
java {
if (System.getenv('DOCKER_ENABLE_SECURITY') == 'false' || System.getenv('DISABLE_ADDITIONAL_FEATURES') == 'true'
|| (project.hasProperty('DISABLE_ADDITIONAL_FEATURES')
&& System.getProperty('DISABLE_ADDITIONAL_FEATURES') == 'true')) {
exclude 'stirling/software/proprietary/security/**'
}
if (System.getenv('STIRLING_PDF_DESKTOP_UI') == 'false') {
exclude 'stirling/software/SPDF/UI/impl/**'
}
@@ -31,6 +31,8 @@ import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Enumeration;
import lombok.Getter;
import lombok.Setter;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSException;
@@ -44,8 +46,21 @@ import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
public abstract class CreateSignatureBase implements SignatureInterface {
private PrivateKey privateKey;
@Getter
private Certificate[] certificateChain;
@Setter
private String tsaUrl;
/**
* Specifies whether the external signing scenario should be used.
* If set to {@code true}, external signing will be performed and
* {@link SignatureInterface} will be used for signing.
* If set to {@code false}, internal signing will be performed.
* <p>Default: {@code false}
*
* @param externalSigning {@code true} if external signing should be performed; {@code false} for internal signing
*/
@Setter
@Getter
private boolean externalSigning;
/**
@@ -97,18 +112,10 @@ public abstract class CreateSignatureBase implements SignatureInterface {
this.privateKey = privateKey;
}
public Certificate[] getCertificateChain() {
return certificateChain;
}
public final void setCertificateChain(final Certificate[] certificateChain) {
this.certificateChain = certificateChain;
}
public void setTsaUrl(String tsaUrl) {
this.tsaUrl = tsaUrl;
}
/**
* SignatureInterface sample implementation.
*
@@ -152,19 +159,4 @@ public abstract class CreateSignatureBase implements SignatureInterface {
}
}
public boolean isExternalSigning() {
return externalSigning;
}
/**
* Set if external signing scenario should be used. If {@code false}, SignatureInterface would
* be used for signing.
*
* <p>Default: {@code false}
*
* @param externalSigning {@code true} if external signing should be performed
*/
public void setExternalSigning(boolean externalSigning) {
this.externalSigning = externalSigning;
}
}
@@ -10,6 +10,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;
@@ -22,10 +23,10 @@ import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.UI.WebBrowser;
import stirling.software.common.configuration.AppConfig;
import stirling.software.common.configuration.ConfigInitializer;
import stirling.software.common.configuration.InstallationPathConfig;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.util.UrlUtils;
@Slf4j
@@ -44,16 +45,15 @@ public class SPDFApplication {
private final AppConfig appConfig;
private final Environment env;
private final ApplicationProperties applicationProperties;
// private final WebBrowser webBrowser; // Removed - desktop UI eliminated
private final WebBrowser webBrowser;
public SPDFApplication(
AppConfig appConfig, Environment env, ApplicationProperties applicationProperties) {
AppConfig appConfig,
Environment env,
@Autowired(required = false) WebBrowser webBrowser) {
this.appConfig = appConfig;
this.env = env;
this.applicationProperties = applicationProperties;
// this.webBrowser = webBrowser; // Removed - desktop UI eliminated
this.webBrowser = webBrowser;
}
public static void main(String[] args) throws IOException, InterruptedException {
@@ -147,31 +147,28 @@ public class SPDFApplication {
serverPortStatic = serverPort;
String url = baseUrl + ":" + getStaticPort() + contextPath;
// Desktop UI initialization removed - webBrowser dependency eliminated
// Keep backwards compatibility for STIRLING_PDF_DESKTOP_UI system property
if (Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) {
log.info("Desktop UI mode enabled, but WebBrowser functionality has been removed");
// webBrowser.initWebUI(url); // Removed - desktop UI eliminated
}
if (webBrowser != null
&& Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) {
webBrowser.initWebUI(url);
} else {
String browserOpenEnv = env.getProperty("BROWSER_OPEN");
boolean browserOpen = browserOpenEnv != null && "true".equalsIgnoreCase(browserOpenEnv);
if (browserOpen) {
try {
String os = System.getProperty("os.name").toLowerCase();
Runtime rt = Runtime.getRuntime();
// Standard browser opening logic
String browserOpenEnv = env.getProperty("BROWSER_OPEN");
boolean browserOpen = browserOpenEnv != null && "true".equalsIgnoreCase(browserOpenEnv);
if (browserOpen) {
try {
String os = System.getProperty("os.name").toLowerCase();
Runtime rt = Runtime.getRuntime();
if (os.contains("win")) {
// For Windows
SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url);
} else if (os.contains("mac")) {
SystemCommand.runCommand(rt, "open " + url);
} else if (os.contains("nix") || os.contains("nux")) {
SystemCommand.runCommand(rt, "xdg-open " + url);
if (os.contains("win")) {
// For Windows
SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url);
} else if (os.contains("mac")) {
SystemCommand.runCommand(rt, "open " + url);
} else if (os.contains("nix") || os.contains("nux")) {
SystemCommand.runCommand(rt, "xdg-open " + url);
}
} catch (IOException e) {
log.error("Error opening browser: {}", e.getMessage());
}
} catch (IOException e) {
log.error("Error opening browser: {}", e.getMessage());
}
}
}
@@ -188,10 +185,9 @@ public class SPDFApplication {
@PreDestroy
public void cleanup() {
// webBrowser cleanup removed - desktop UI eliminated
// if (webBrowser != null) {
// webBrowser.cleanup();
// }
if (webBrowser != null) {
webBrowser.cleanup();
}
}
private static void printStartupLogs() {
@@ -0,0 +1,7 @@
package stirling.software.SPDF.UI;
public interface WebBrowser {
void initWebUI(String url);
void cleanup();
}
@@ -0,0 +1,497 @@
package stirling.software.SPDF.UI.impl;
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.WindowEvent;
import java.awt.event.WindowStateListener;
import java.io.File;
import java.io.InputStream;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import org.cef.CefApp;
import org.cef.CefClient;
import org.cef.CefSettings;
import org.cef.browser.CefBrowser;
import org.cef.callback.CefBeforeDownloadCallback;
import org.cef.callback.CefDownloadItem;
import org.cef.callback.CefDownloadItemCallback;
import org.cef.handler.CefDownloadHandlerAdapter;
import org.cef.handler.CefLoadHandlerAdapter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import me.friwi.jcefmaven.CefAppBuilder;
import me.friwi.jcefmaven.EnumProgress;
import me.friwi.jcefmaven.MavenCefAppHandlerAdapter;
import me.friwi.jcefmaven.impl.progress.ConsoleProgressHandler;
import stirling.software.SPDF.UI.WebBrowser;
import stirling.software.common.configuration.InstallationPathConfig;
import stirling.software.common.util.UIScaling;
@Component
@Slf4j
@ConditionalOnProperty(
name = "STIRLING_PDF_DESKTOP_UI",
havingValue = "true",
matchIfMissing = false)
public class DesktopBrowser implements WebBrowser {
private static CefApp cefApp;
private static CefClient client;
private static CefBrowser browser;
private static JFrame frame;
private static LoadingWindow loadingWindow;
private static volatile boolean browserInitialized = false;
private static TrayIcon trayIcon;
private static SystemTray systemTray;
public DesktopBrowser() {
SwingUtilities.invokeLater(
() -> {
loadingWindow = new LoadingWindow(null, "Initializing...");
loadingWindow.setVisible(true);
});
}
public void initWebUI(String url) {
CompletableFuture.runAsync(
() -> {
try {
CefAppBuilder builder = new CefAppBuilder();
configureCefSettings(builder);
builder.setProgressHandler(createProgressHandler());
builder.setInstallDir(
new File(InstallationPathConfig.getClientWebUIPath()));
// Build and initialize CEF
cefApp = builder.build();
client = cefApp.createClient();
// Set up download handler
setupDownloadHandler();
// Create browser and frame on EDT
SwingUtilities.invokeAndWait(
() -> {
browser = client.createBrowser(url, false, false);
setupMainFrame();
setupLoadHandler();
// Force initialize UI after 7 seconds if not already done
Timer timeoutTimer =
new Timer(
2500,
e -> {
log.warn(
"Loading timeout reached. Forcing"
+ " UI transition.");
if (!browserInitialized) {
// Force UI initialization
forceInitializeUI();
}
});
timeoutTimer.setRepeats(false);
timeoutTimer.start();
});
} catch (Exception e) {
log.error("Error initializing JCEF browser: ", e);
cleanup();
}
});
}
private void configureCefSettings(CefAppBuilder builder) {
CefSettings settings = builder.getCefSettings();
String basePath = InstallationPathConfig.getClientWebUIPath();
log.info("basePath " + basePath);
settings.cache_path = new File(basePath + "cache").getAbsolutePath();
settings.root_cache_path = new File(basePath + "root_cache").getAbsolutePath();
// settings.browser_subprocess_path = new File(basePath +
// "subprocess").getAbsolutePath();
// settings.resources_dir_path = new File(basePath + "resources").getAbsolutePath();
// settings.locales_dir_path = new File(basePath + "locales").getAbsolutePath();
settings.log_file = new File(basePath, "debug.log").getAbsolutePath();
settings.persist_session_cookies = true;
settings.windowless_rendering_enabled = false;
settings.log_severity = CefSettings.LogSeverity.LOGSEVERITY_INFO;
builder.setAppHandler(
new MavenCefAppHandlerAdapter() {
@Override
public void stateHasChanged(org.cef.CefApp.CefAppState state) {
log.info("CEF state changed: " + state);
if (state == CefApp.CefAppState.TERMINATED) {
System.exit(0);
}
}
});
}
private void setupDownloadHandler() {
client.addDownloadHandler(
new CefDownloadHandlerAdapter() {
@Override
public boolean onBeforeDownload(
CefBrowser browser,
CefDownloadItem downloadItem,
String suggestedName,
CefBeforeDownloadCallback callback) {
callback.Continue("", true);
return true;
}
@Override
public void onDownloadUpdated(
CefBrowser browser,
CefDownloadItem downloadItem,
CefDownloadItemCallback callback) {
if (downloadItem.isComplete()) {
log.info("Download completed: " + downloadItem.getFullPath());
} else if (downloadItem.isCanceled()) {
log.info("Download canceled: " + downloadItem.getFullPath());
}
}
});
}
private ConsoleProgressHandler createProgressHandler() {
return new ConsoleProgressHandler() {
@Override
public void handleProgress(EnumProgress state, float percent) {
Objects.requireNonNull(state, "state cannot be null");
SwingUtilities.invokeLater(
() -> {
if (loadingWindow != null) {
switch (state) {
case LOCATING:
loadingWindow.setStatus("Locating Files...");
loadingWindow.setProgress(0);
break;
case DOWNLOADING:
if (percent >= 0) {
loadingWindow.setStatus(
String.format(
"Downloading additional files: %.0f%%",
percent));
loadingWindow.setProgress((int) percent);
}
break;
case EXTRACTING:
loadingWindow.setStatus("Extracting files...");
loadingWindow.setProgress(60);
break;
case INITIALIZING:
loadingWindow.setStatus("Initializing UI...");
loadingWindow.setProgress(80);
break;
case INITIALIZED:
loadingWindow.setStatus("Finalising startup...");
loadingWindow.setProgress(90);
break;
}
}
});
}
};
}
private void setupMainFrame() {
frame = new JFrame("Stirling-PDF");
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setUndecorated(true);
frame.setOpacity(0.0f);
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setDoubleBuffered(true);
contentPane.add(browser.getUIComponent(), BorderLayout.CENTER);
frame.setContentPane(contentPane);
frame.addWindowListener(
new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
cleanup();
System.exit(0);
}
});
frame.setSize(UIScaling.scaleWidth(1280), UIScaling.scaleHeight(800));
frame.setLocationRelativeTo(null);
loadIcon();
}
private void setupLoadHandler() {
final long initStartTime = System.currentTimeMillis();
log.info("Setting up load handler at: {}", initStartTime);
client.addLoadHandler(
new CefLoadHandlerAdapter() {
@Override
public void onLoadingStateChange(
CefBrowser browser,
boolean isLoading,
boolean canGoBack,
boolean canGoForward) {
log.debug(
"Loading state change - isLoading: {}, canGoBack: {}, canGoForward:"
+ " {}, browserInitialized: {}, Time elapsed: {}ms",
isLoading,
canGoBack,
canGoForward,
browserInitialized,
System.currentTimeMillis() - initStartTime);
if (!isLoading && !browserInitialized) {
log.info(
"Browser finished loading, preparing to initialize UI"
+ " components");
browserInitialized = true;
SwingUtilities.invokeLater(
() -> {
try {
if (loadingWindow != null) {
log.info("Starting UI initialization sequence");
// Close loading window first
loadingWindow.setVisible(false);
loadingWindow.dispose();
loadingWindow = null;
log.info("Loading window disposed");
// Then setup the main frame
frame.setVisible(false);
frame.dispose();
frame.setOpacity(1.0f);
frame.setUndecorated(false);
frame.pack();
frame.setSize(
UIScaling.scaleWidth(1280),
UIScaling.scaleHeight(800));
frame.setLocationRelativeTo(null);
log.debug("Frame reconfigured");
// Show the main frame
frame.setVisible(true);
frame.requestFocus();
frame.toFront();
log.info("Main frame displayed and focused");
// Focus the browser component
Timer focusTimer =
new Timer(
100,
e -> {
try {
browser.getUIComponent()
.requestFocus();
log.info(
"Browser component"
+ " focused");
} catch (Exception ex) {
log.error(
"Error focusing"
+ " browser",
ex);
}
});
focusTimer.setRepeats(false);
focusTimer.start();
}
} catch (Exception e) {
log.error("Error during UI initialization", e);
// Attempt cleanup on error
if (loadingWindow != null) {
loadingWindow.dispose();
loadingWindow = null;
}
if (frame != null) {
frame.setVisible(true);
frame.requestFocus();
}
}
});
}
}
});
}
private void setupTrayIcon(Image icon) {
if (!SystemTray.isSupported()) {
log.warn("System tray is not supported");
return;
}
try {
systemTray = SystemTray.getSystemTray();
// Create popup menu
PopupMenu popup = new PopupMenu();
// Create menu items
MenuItem showItem = new MenuItem("Show");
showItem.addActionListener(
e -> {
frame.setVisible(true);
frame.setState(Frame.NORMAL);
});
MenuItem exitItem = new MenuItem("Exit");
exitItem.addActionListener(
e -> {
cleanup();
System.exit(0);
});
// Add menu items to popup menu
popup.add(showItem);
popup.addSeparator();
popup.add(exitItem);
// Create tray icon
trayIcon = new TrayIcon(icon, "Stirling-PDF", popup);
trayIcon.setImageAutoSize(true);
// Add double-click behavior
trayIcon.addActionListener(
e -> {
frame.setVisible(true);
frame.setState(Frame.NORMAL);
});
// Add tray icon to system tray
systemTray.add(trayIcon);
// Modify frame behavior to minimize to tray
frame.addWindowStateListener(
new WindowStateListener() {
public void windowStateChanged(WindowEvent e) {
if (e.getNewState() == Frame.ICONIFIED) {
frame.setVisible(false);
}
}
});
} catch (AWTException e) {
log.error("Error setting up system tray icon", e);
}
}
private void loadIcon() {
try {
Image icon = null;
String[] iconPaths = {"/static/favicon.ico"};
for (String path : iconPaths) {
if (icon != null) break;
try {
try (InputStream is = getClass().getResourceAsStream(path)) {
if (is != null) {
icon = ImageIO.read(is);
break;
}
}
} catch (Exception e) {
log.debug("Could not load icon from " + path, e);
}
}
if (icon != null) {
frame.setIconImage(icon);
setupTrayIcon(icon);
} else {
log.warn("Could not load icon from any source");
}
} catch (Exception e) {
log.error("Error loading icon", e);
}
}
@PreDestroy
public void cleanup() {
if (browser != null) browser.close(true);
if (client != null) client.dispose();
if (cefApp != null) cefApp.dispose();
if (loadingWindow != null) loadingWindow.dispose();
}
public static void forceInitializeUI() {
try {
if (loadingWindow != null) {
log.info("Forcing start of UI initialization sequence");
// Close loading window first
loadingWindow.setVisible(false);
loadingWindow.dispose();
loadingWindow = null;
log.info("Loading window disposed");
// Then setup the main frame
frame.setVisible(false);
frame.dispose();
frame.setOpacity(1.0f);
frame.setUndecorated(false);
frame.pack();
frame.setSize(UIScaling.scaleWidth(1280), UIScaling.scaleHeight(800));
frame.setLocationRelativeTo(null);
log.debug("Frame reconfigured");
// Show the main frame
frame.setVisible(true);
frame.requestFocus();
frame.toFront();
log.info("Main frame displayed and focused");
// Focus the browser component if available
if (browser != null) {
Timer focusTimer =
new Timer(
100,
e -> {
try {
browser.getUIComponent().requestFocus();
log.info("Browser component focused");
} catch (Exception ex) {
log.error(
"Error focusing browser during force ui"
+ " initialization.",
ex);
}
});
focusTimer.setRepeats(false);
focusTimer.start();
}
}
} catch (Exception e) {
log.error("Error during Forced UI initialization.", e);
// Attempt cleanup on error
if (loadingWindow != null) {
loadingWindow.dispose();
loadingWindow = null;
}
if (frame != null) {
frame.setVisible(true);
frame.setOpacity(1.0f);
frame.setUndecorated(false);
frame.requestFocus();
}
}
}
}
@@ -0,0 +1,351 @@
package stirling.software.SPDF.UI.impl;
import java.awt.*;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import javax.swing.*;
import io.github.pixee.security.BoundedLineReader;
import lombok.extern.slf4j.Slf4j;
import stirling.software.common.util.UIScaling;
@Slf4j
public class LoadingWindow extends JDialog {
private final JProgressBar progressBar;
private final JLabel statusLabel;
private final JPanel mainPanel;
private final JLabel brandLabel;
private long startTime;
private Timer stuckTimer;
private long stuckThreshold = 4000;
private long timeAt90Percent = -1;
private volatile Process explorerProcess;
private static final boolean IS_WINDOWS =
System.getProperty("os.name").toLowerCase().contains("win");
public LoadingWindow(Frame parent, String initialUrl) {
super(parent, "Initializing Stirling-PDF", true);
startTime = System.currentTimeMillis();
log.info("Creating LoadingWindow - initialization started at: {}", startTime);
// Initialize components
mainPanel = new JPanel();
mainPanel.setBackground(Color.WHITE);
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 30, 20, 30));
mainPanel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
// Configure GridBagConstraints
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(5, 5, 5, 5);
gbc.weightx = 1.0;
gbc.weighty = 0.0;
// Add icon
try {
try (InputStream is = getClass().getResourceAsStream("/static/favicon.ico")) {
if (is != null) {
Image img = ImageIO.read(is);
if (img != null) {
Image scaledImg = UIScaling.scaleIcon(img, 48, 48);
JLabel iconLabel = new JLabel(new ImageIcon(scaledImg));
iconLabel.setHorizontalAlignment(SwingConstants.CENTER);
gbc.gridy = 0;
mainPanel.add(iconLabel, gbc);
log.info("Icon loaded and scaled successfully");
}
}
}
} catch (Exception e) {
log.error("Failed to load icon", e);
}
// URL Label with explicit size
brandLabel = new JLabel(initialUrl);
brandLabel.setHorizontalAlignment(SwingConstants.CENTER);
brandLabel.setPreferredSize(new Dimension(300, 25));
brandLabel.setText("Stirling-PDF");
gbc.gridy = 1;
mainPanel.add(brandLabel, gbc);
// Status label with explicit size
statusLabel = new JLabel("Initializing...");
statusLabel.setHorizontalAlignment(SwingConstants.CENTER);
statusLabel.setPreferredSize(new Dimension(300, 25));
gbc.gridy = 2;
mainPanel.add(statusLabel, gbc);
// Progress bar with explicit size
progressBar = new JProgressBar(0, 100);
progressBar.setStringPainted(true);
progressBar.setPreferredSize(new Dimension(300, 25));
gbc.gridy = 3;
mainPanel.add(progressBar, gbc);
// Set dialog properties
setContentPane(mainPanel);
setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
setResizable(false);
setUndecorated(false);
// Set size and position
setSize(UIScaling.scaleWidth(400), UIScaling.scaleHeight(200));
setLocationRelativeTo(parent);
setAlwaysOnTop(true);
setProgress(0);
setStatus("Starting...");
log.info(
"LoadingWindow initialization completed in {}ms",
System.currentTimeMillis() - startTime);
}
private void checkAndRefreshExplorer() {
if (!IS_WINDOWS) {
return;
}
if (timeAt90Percent == -1) {
timeAt90Percent = System.currentTimeMillis();
stuckTimer =
new Timer(
1000,
e -> {
long currentTime = System.currentTimeMillis();
if (currentTime - timeAt90Percent > stuckThreshold) {
try {
log.debug(
"Attempting Windows explorer refresh due to 90% stuck state");
String currentDir = System.getProperty("user.dir");
// Store current explorer PIDs before we start new one
Set<String> existingPids = new HashSet<>();
ProcessBuilder listExplorer =
new ProcessBuilder(
"cmd",
"/c",
"wmic",
"process",
"where",
"name='explorer.exe'",
"get",
"ProcessId",
"/format:csv");
Process process = listExplorer.start();
BufferedReader reader =
new BufferedReader(
new InputStreamReader(
process.getInputStream()));
String line;
while ((line =
BoundedLineReader.readLine(
reader, 5_000_000))
!= null) {
if (line.matches(".*\\d+.*")) { // Contains numbers
String[] parts = line.trim().split(",");
if (parts.length >= 2) {
existingPids.add(
parts[parts.length - 1].trim());
}
}
}
process.waitFor(2, TimeUnit.SECONDS);
// Start new explorer
ProcessBuilder pb =
new ProcessBuilder(
"cmd",
"/c",
"start",
"/min",
"/b",
"explorer.exe",
currentDir);
pb.redirectErrorStream(true);
explorerProcess = pb.start();
// Schedule cleanup
Timer cleanupTimer =
new Timer(
2000,
cleanup -> {
try {
// Find new explorer processes
ProcessBuilder findNewExplorer =
new ProcessBuilder(
"cmd",
"/c",
"wmic",
"process",
"where",
"name='explorer.exe'",
"get",
"ProcessId",
"/format:csv");
Process newProcess =
findNewExplorer.start();
BufferedReader newReader =
new BufferedReader(
new InputStreamReader(
newProcess
.getInputStream()));
String newLine;
while ((newLine =
BoundedLineReader
.readLine(
newReader,
5_000_000))
!= null) {
if (newLine.matches(
".*\\d+.*")) {
String[] parts =
newLine.trim()
.split(",");
if (parts.length >= 2) {
String pid =
parts[
parts.length
- 1]
.trim();
if (!existingPids
.contains(
pid)) {
log.debug(
"Found new explorer.exe with PID: "
+ pid);
ProcessBuilder
killProcess =
new ProcessBuilder(
"taskkill",
"/PID",
pid,
"/F");
killProcess
.redirectErrorStream(
true);
Process killResult =
killProcess
.start();
killResult.waitFor(
2,
TimeUnit
.SECONDS);
log.debug(
"Explorer process terminated: "
+ pid);
}
}
}
}
newProcess.waitFor(
2, TimeUnit.SECONDS);
} catch (Exception ex) {
log.error(
"Error cleaning up Windows explorer process",
ex);
}
});
cleanupTimer.setRepeats(false);
cleanupTimer.start();
stuckTimer.stop();
} catch (Exception ex) {
log.error("Error refreshing Windows explorer", ex);
}
}
});
stuckTimer.setRepeats(true);
stuckTimer.start();
}
}
public void setProgress(final int progress) {
SwingUtilities.invokeLater(
() -> {
try {
int validProgress = Math.min(Math.max(progress, 0), 100);
log.info(
"Setting progress to {}% at {}ms since start",
validProgress, System.currentTimeMillis() - startTime);
// Log additional details when near 90%
if (validProgress >= 85 && validProgress <= 95) {
log.info(
"Near 90% progress - Current status: {}, Window visible: {}, "
+ "Progress bar responding: {}, Memory usage: {}MB",
statusLabel.getText(),
isVisible(),
progressBar.isEnabled(),
Runtime.getRuntime().totalMemory() / (1024 * 1024));
// Add thread state logging
Thread currentThread = Thread.currentThread();
log.info(
"Current thread state - Name: {}, State: {}, Priority: {}",
currentThread.getName(),
currentThread.getState(),
currentThread.getPriority());
if (validProgress >= 90 && validProgress < 95) {
checkAndRefreshExplorer();
} else {
// Reset the timer if we move past 95%
if (validProgress >= 95) {
if (stuckTimer != null) {
stuckTimer.stop();
}
timeAt90Percent = -1;
}
}
}
progressBar.setValue(validProgress);
progressBar.setString(validProgress + "%");
mainPanel.revalidate();
mainPanel.repaint();
} catch (Exception e) {
log.error("Error updating progress to " + progress, e);
}
});
}
public void setStatus(final String status) {
log.info(
"Status update at {}ms - Setting status to: {}",
System.currentTimeMillis() - startTime,
status);
SwingUtilities.invokeLater(
() -> {
try {
String validStatus = status != null ? status : "";
statusLabel.setText(validStatus);
// Log UI state when status changes
log.info(
"UI State - Window visible: {}, Progress: {}%, Status: {}",
isVisible(), progressBar.getValue(), validStatus);
mainPanel.revalidate();
mainPanel.repaint();
} catch (Exception e) {
log.error("Error updating status to: " + status, e);
}
});
}
@Override
public void dispose() {
log.info("LoadingWindow disposing after {}ms", System.currentTimeMillis() - startTime);
super.dispose();
}
}
@@ -20,6 +20,8 @@ public class CleanUrlInterceptor implements HandlerInterceptor {
"endpoints",
"logout",
"error",
"days",
"date",
"errorOAuth",
"file",
"messageType",
@@ -6,6 +6,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@@ -19,6 +20,7 @@ public class EndpointConfiguration {
private static final String REMOVE_BLANKS = "remove-blanks";
private final ApplicationProperties applicationProperties;
@Getter
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>();
private Set<String> disabledGroups = new HashSet<>();
@@ -46,10 +48,6 @@ public class EndpointConfiguration {
endpointStatuses.put(endpoint, false);
}
public Map<String, Boolean> getEndpointStatuses() {
return endpointStatuses;
}
public boolean isEndpointEnabled(String endpoint) {
String original = endpoint;
if (endpoint.startsWith("/")) {
@@ -6,8 +6,6 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
@@ -18,11 +16,12 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Component
@RequiredArgsConstructor
@Slf4j
public class EndpointInspector implements ApplicationListener<ContextRefreshedEvent> {
private static final Logger logger = LoggerFactory.getLogger(EndpointInspector.class);
private final ApplicationContext applicationContext;
private final Set<String> validGetEndpoints = new HashSet<>();
@@ -71,13 +70,13 @@ public class EndpointInspector implements ApplicationListener<ContextRefreshedEv
}
if (validGetEndpoints.isEmpty()) {
logger.warn("No endpoints discovered. Adding common endpoints as fallback.");
log.warn("No endpoints discovered. Adding common endpoints as fallback.");
validGetEndpoints.add("/");
validGetEndpoints.add("/api/**");
validGetEndpoints.add("/**");
}
} catch (Exception e) {
logger.error("Error discovering endpoints", e);
log.error("Error discovering endpoints", e);
}
}
@@ -203,10 +202,10 @@ public class EndpointInspector implements ApplicationListener<ContextRefreshedEv
private void logAllEndpoints() {
Set<String> sortedEndpoints = new TreeSet<>(validGetEndpoints);
logger.info("=== BEGIN: All discovered GET endpoints ===");
log.info("=== BEGIN: All discovered GET endpoints ===");
for (String endpoint : sortedEndpoints) {
logger.info("Endpoint: {}", endpoint);
log.info("Endpoint: {}", endpoint);
}
logger.info("=== END: All discovered GET endpoints ===");
log.info("=== END: All discovered GET endpoints ===");
}
}
@@ -10,7 +10,6 @@ import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import lombok.RequiredArgsConstructor;
@@ -42,8 +41,7 @@ public class OpenApiConfig {
new License()
.name("MIT")
.url(
"https://raw.githubusercontent.com/Stirling-Tools/Stirling-PDF/refs/heads/main/LICENSE")
.identifier("MIT"))
"https://raw.githubusercontent.com/Stirling-Tools/Stirling-PDF/refs/heads/main/LICENSE"))
.termsOfService("https://www.stirlingpdf.com/terms")
.contact(
new Contact()
@@ -51,25 +49,17 @@ public class OpenApiConfig {
.url("https://www.stirlingpdf.com")
.email("contact@stirlingpdf.com"))
.description(DEFAULT_DESCRIPTION);
OpenAPI openAPI = new OpenAPI().info(info);
// Add server configuration from environment variable
String swaggerServerUrl = System.getenv("SWAGGER_SERVER_URL");
if (swaggerServerUrl != null && !swaggerServerUrl.trim().isEmpty()) {
Server server = new Server().url(swaggerServerUrl).description("API Server");
openAPI.addServersItem(server);
}
if (!applicationProperties.getSecurity().getEnableLogin()) {
return openAPI.components(new Components());
return new OpenAPI().components(new Components()).info(info);
} else {
SecurityScheme apiKeyScheme =
new SecurityScheme()
.type(SecurityScheme.Type.APIKEY)
.in(SecurityScheme.In.HEADER)
.name("X-API-KEY");
return openAPI.components(new Components().addSecuritySchemes("apiKey", apiKeyScheme))
return new OpenAPI()
.components(new Components().addSecuritySchemes("apiKey", apiKeyScheme))
.info(info)
.addSecurityItem(new SecurityRequirement().addList("apiKey"));
}
}
@@ -2,10 +2,13 @@ package stirling.software.SPDF.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import lombok.RequiredArgsConstructor;
import stirling.software.common.configuration.InstallationPathConfig;
@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
@@ -17,12 +20,12 @@ public class WebMvcConfig implements WebMvcConfigurer {
registry.addInterceptor(endpointInterceptor);
}
// @Override
// public void addResourceHandlers(ResourceHandlerRegistry registry) {
// // Handler for external static resources - DISABLED in backend-only mode
// registry.addResourceHandler("/**")
// .addResourceLocations(
// "file:" + InstallationPathConfig.getStaticPath(), "classpath:/static/");
// // .setCachePeriod(0); // Optional: disable caching
// }
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// Handler for external static resources
registry.addResourceHandler("/**")
.addResourceLocations(
"file:" + InstallationPathConfig.getStaticPath(), "classpath:/static/");
// .setCachePeriod(0); // Optional: disable caching
}
}
@@ -18,7 +18,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.CustomPDFDocumentFactory;
@@ -30,7 +29,7 @@ public class AnalysisController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/page-count", consumes = "multipart/form-data")
@PostMapping(value = "/page-count", consumes = "multipart/form-data")
@Operation(
summary = "Get PDF page count",
description = "Returns total number of pages in PDF. Input:PDF Output:JSON Type:SISO")
@@ -40,7 +39,7 @@ public class AnalysisController {
}
}
@AutoJobPostMapping(value = "/basic-info", consumes = "multipart/form-data")
@PostMapping(value = "/basic-info", consumes = "multipart/form-data")
@Operation(
summary = "Get basic PDF information",
description = "Returns page count, version, file size. Input:PDF Output:JSON Type:SISO")
@@ -54,7 +53,7 @@ public class AnalysisController {
}
}
@AutoJobPostMapping(value = "/document-properties", consumes = "multipart/form-data")
@PostMapping(value = "/document-properties", consumes = "multipart/form-data")
@Operation(
summary = "Get PDF document properties",
description = "Returns title, author, subject, etc. Input:PDF Output:JSON Type:SISO")
@@ -77,7 +76,7 @@ public class AnalysisController {
}
}
@AutoJobPostMapping(value = "/page-dimensions", consumes = "multipart/form-data")
@PostMapping(value = "/page-dimensions", consumes = "multipart/form-data")
@Operation(
summary = "Get page dimensions for all pages",
description = "Returns width and height of each page. Input:PDF Output:JSON Type:SISO")
@@ -97,7 +96,7 @@ public class AnalysisController {
}
}
@AutoJobPostMapping(value = "/form-fields", consumes = "multipart/form-data")
@PostMapping(value = "/form-fields", consumes = "multipart/form-data")
@Operation(
summary = "Get form field information",
description =
@@ -120,7 +119,7 @@ public class AnalysisController {
}
}
@AutoJobPostMapping(value = "/annotation-info", consumes = "multipart/form-data")
@PostMapping(value = "/annotation-info", consumes = "multipart/form-data")
@Operation(
summary = "Get annotation information",
description = "Returns count and types of annotations. Input:PDF Output:JSON Type:SISO")
@@ -144,7 +143,7 @@ public class AnalysisController {
}
}
@AutoJobPostMapping(value = "/font-info", consumes = "multipart/form-data")
@PostMapping(value = "/font-info", consumes = "multipart/form-data")
@Operation(
summary = "Get font information",
description =
@@ -166,7 +165,7 @@ public class AnalysisController {
}
}
@AutoJobPostMapping(value = "/security-info", consumes = "multipart/form-data")
@PostMapping(value = "/security-info", consumes = "multipart/form-data")
@Operation(
summary = "Get security information",
description =
@@ -12,6 +12,7 @@ import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -21,7 +22,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.model.api.general.CropPdfForm;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.WebResponseUtils;
@@ -33,7 +33,7 @@ public class CropController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/crop", consumes = "multipart/form-data")
@PostMapping(value = "/crop", consumes = "multipart/form-data")
@Operation(
summary = "Crops a PDF document",
description =
@@ -6,6 +6,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline;
@@ -14,6 +16,7 @@ import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlin
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@@ -30,7 +33,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.EditTableOfContentsRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.WebResponseUtils;
@@ -44,7 +46,7 @@ public class EditTableOfContentsController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
private final ObjectMapper objectMapper;
@AutoJobPostMapping(value = "/extract-bookmarks", consumes = "multipart/form-data")
@PostMapping(value = "/extract-bookmarks", consumes = "multipart/form-data")
@Operation(
summary = "Extract PDF Bookmarks",
description = "Extracts bookmarks/table of contents from a PDF document as JSON.")
@@ -152,7 +154,7 @@ public class EditTableOfContentsController {
return bookmark;
}
@AutoJobPostMapping(value = "/edit-table-of-contents", consumes = "multipart/form-data")
@PostMapping(value = "/edit-table-of-contents", consumes = "multipart/form-data")
@Operation(
summary = "Edit Table of Contents",
description = "Add or edit bookmarks/table of contents in a PDF document.")
@@ -234,33 +236,12 @@ public class EditTableOfContentsController {
}
// Inner class to represent bookmarks in JSON
@Setter
@Getter
public static class BookmarkItem {
private String title;
private int pageNumber;
private List<BookmarkItem> children = new ArrayList<>();
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getPageNumber() {
return pageNumber;
}
public void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
}
public List<BookmarkItem> getChildren() {
return children;
}
public void setChildren(List<BookmarkItem> children) {
this.children = children;
}
}
}
@@ -22,6 +22,7 @@ import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -33,7 +34,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.general.MergePdfsRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.GeneralUtils;
@@ -154,7 +154,7 @@ public class MergeController {
}
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/merge-pdfs")
@PostMapping(consumes = "multipart/form-data", value = "/merge-pdfs")
@Operation(
summary = "Merge multiple PDF files into one",
description =
@@ -13,6 +13,7 @@ import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.util.Matrix;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -24,7 +25,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.model.api.general.MergeMultiplePagesRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.WebResponseUtils;
@@ -36,7 +36,7 @@ public class MultiPageLayoutController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/multi-page-layout", consumes = "multipart/form-data")
@PostMapping(value = "/multi-page-layout", consumes = "multipart/form-data")
@Operation(
summary = "Merge multiple pages of a PDF document into a single page",
description =
@@ -6,6 +6,7 @@ import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -15,7 +16,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.service.PdfImageRemovalService;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.WebResponseUtils;
@@ -46,7 +46,7 @@ public class PdfImageRemovalController {
* content type and filename.
* @throws IOException If an error occurs while processing the PDF file.
*/
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/remove-image-pdf")
@PostMapping(consumes = "multipart/form-data", value = "/remove-image-pdf")
@Operation(
summary = "Remove images from file to reduce the file size.",
description =
@@ -15,6 +15,7 @@ import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -26,7 +27,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.model.api.general.OverlayPdfsRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.GeneralUtils;
import stirling.software.common.util.WebResponseUtils;
@@ -39,7 +39,7 @@ public class PdfOverlayController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/overlay-pdfs", consumes = "multipart/form-data")
@PostMapping(value = "/overlay-pdfs", consumes = "multipart/form-data")
@Operation(
summary = "Overlay PDF files in various modes",
description =
@@ -9,6 +9,7 @@ import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -23,7 +24,6 @@ import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.SortTypes;
import stirling.software.SPDF.model.api.PDFWithPageNums;
import stirling.software.SPDF.model.api.general.RearrangePagesRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.GeneralUtils;
@@ -38,7 +38,7 @@ public class RearrangePagesPDFController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/remove-pages")
@PostMapping(consumes = "multipart/form-data", value = "/remove-pages")
@Operation(
summary = "Remove pages from a PDF file",
description =
@@ -237,7 +237,7 @@ public class RearrangePagesPDFController {
}
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/rearrange-pages")
@PostMapping(consumes = "multipart/form-data", value = "/rearrange-pages")
@Operation(
summary = "Rearrange pages in a PDF file",
description =
@@ -7,6 +7,7 @@ import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -18,7 +19,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.model.api.general.RotatePDFRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.WebResponseUtils;
@@ -31,7 +31,7 @@ public class RotationController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/rotate-pdf")
@PostMapping(consumes = "multipart/form-data", value = "/rotate-pdf")
@Operation(
summary = "Rotate a PDF file",
description =
@@ -14,6 +14,7 @@ import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.util.Matrix;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -25,7 +26,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.model.api.general.ScalePagesRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.WebResponseUtils;
@@ -38,7 +38,7 @@ public class ScalePagesController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/scale-pages", consumes = "multipart/form-data")
@PostMapping(value = "/scale-pages", consumes = "multipart/form-data")
@Operation(
summary = "Change the size of a PDF page/document",
description =
@@ -7,6 +7,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -16,7 +17,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.EndpointConfiguration;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.configuration.InstallationPathConfig;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.util.GeneralUtils;
@@ -31,7 +31,7 @@ public class SettingsController {
private final ApplicationProperties applicationProperties;
private final EndpointConfiguration endpointConfiguration;
@AutoJobPostMapping("/update-enable-analytics")
@PostMapping("/update-enable-analytics")
@Hidden
public ResponseEntity<String> updateApiKey(@RequestBody Boolean enabled) throws IOException {
if (applicationProperties.getSystem().getEnableAnalytics() != null) {
@@ -15,6 +15,7 @@ import org.apache.pdfbox.pdmodel.PDPage;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -27,7 +28,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.PDFWithPageNums;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.WebResponseUtils;
@@ -41,7 +41,7 @@ public class SplitPDFController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/split-pages")
@PostMapping(consumes = "multipart/form-data", value = "/split-pages")
@Operation(
summary = "Split a PDF file into separate documents",
description =
@@ -15,6 +15,7 @@ import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlin
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -31,7 +32,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.PdfMetadata;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.service.PdfMetadataService;
@@ -117,7 +117,7 @@ public class SplitPdfByChaptersController {
return bookmarks;
}
@AutoJobPostMapping(value = "/split-pdf-by-chapters", consumes = "multipart/form-data")
@PostMapping(value = "/split-pdf-by-chapters", consumes = "multipart/form-data")
@Operation(
summary = "Split PDFs by Chapters",
description = "Splits a PDF into chapters and returns a ZIP file.")
@@ -20,6 +20,7 @@ import org.apache.pdfbox.util.Matrix;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -31,7 +32,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.WebResponseUtils;
@@ -43,7 +43,7 @@ public class SplitPdfBySectionsController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/split-pdf-by-sections", consumes = "multipart/form-data")
@PostMapping(value = "/split-pdf-by-sections", consumes = "multipart/form-data")
@Operation(
summary = "Split PDF pages into smaller sections",
description =
@@ -12,6 +12,7 @@ import org.apache.pdfbox.pdmodel.PDPage;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -24,7 +25,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.general.SplitPdfBySizeOrCountRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.GeneralUtils;
@@ -39,7 +39,7 @@ public class SplitPdfBySizeController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data")
@PostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data")
@Operation(
summary = "Auto split PDF pages into separate documents based on size or count",
description =
@@ -12,6 +12,7 @@ import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -20,7 +21,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.WebResponseUtils;
@@ -33,7 +33,7 @@ public class ToSinglePageController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf-to-single-page")
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-single-page")
@Operation(
summary = "Convert a multi-page PDF into a single long page PDF",
description =
@@ -1,300 +0,0 @@
package stirling.software.SPDF.controller.api;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Stream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.Dependency;
import stirling.software.SPDF.model.SignatureFile;
import stirling.software.SPDF.service.SignatureService;
import stirling.software.common.configuration.InstallationPathConfig;
import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.service.UserServiceInterface;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.GeneralUtils;
@Slf4j
@RestController
@RequestMapping("/api/v1/ui-data")
@Tag(name = "UI Data", description = "APIs for React UI data")
public class UIDataController {
private final ApplicationProperties applicationProperties;
private final SignatureService signatureService;
private final UserServiceInterface userService;
private final ResourceLoader resourceLoader;
private final RuntimePathConfig runtimePathConfig;
public UIDataController(
ApplicationProperties applicationProperties,
SignatureService signatureService,
@Autowired(required = false) UserServiceInterface userService,
ResourceLoader resourceLoader,
RuntimePathConfig runtimePathConfig) {
this.applicationProperties = applicationProperties;
this.signatureService = signatureService;
this.userService = userService;
this.resourceLoader = resourceLoader;
this.runtimePathConfig = runtimePathConfig;
}
@GetMapping("/home")
@Operation(summary = "Get home page data")
public ResponseEntity<HomeData> getHomeData() {
String showSurvey = System.getenv("SHOW_SURVEY");
boolean showSurveyValue = showSurvey == null || "true".equalsIgnoreCase(showSurvey);
HomeData data = new HomeData();
data.setShowSurveyFromDocker(showSurveyValue);
return ResponseEntity.ok(data);
}
@GetMapping("/licenses")
@Operation(summary = "Get third-party licenses data")
public ResponseEntity<LicensesData> getLicensesData() {
LicensesData data = new LicensesData();
Resource resource = new ClassPathResource("static/3rdPartyLicenses.json");
try {
InputStream is = resource.getInputStream();
String json = new String(is.readAllBytes(), StandardCharsets.UTF_8);
ObjectMapper mapper = new ObjectMapper();
Map<String, List<Dependency>> licenseData =
mapper.readValue(json, new TypeReference<>() {});
data.setDependencies(licenseData.get("dependencies"));
} catch (IOException e) {
log.error("Failed to load licenses data", e);
data.setDependencies(Collections.emptyList());
}
return ResponseEntity.ok(data);
}
@GetMapping("/pipeline")
@Operation(summary = "Get pipeline configuration data")
public ResponseEntity<PipelineData> getPipelineData() {
PipelineData data = new PipelineData();
List<String> pipelineConfigs = new ArrayList<>();
List<Map<String, String>> pipelineConfigsWithNames = new ArrayList<>();
if (new java.io.File(runtimePathConfig.getPipelineDefaultWebUiConfigs()).exists()) {
try (Stream<Path> paths =
Files.walk(Paths.get(runtimePathConfig.getPipelineDefaultWebUiConfigs()))) {
List<Path> jsonFiles =
paths.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".json"))
.toList();
for (Path jsonFile : jsonFiles) {
String content = Files.readString(jsonFile, StandardCharsets.UTF_8);
pipelineConfigs.add(content);
}
for (String config : pipelineConfigs) {
Map<String, Object> jsonContent =
new ObjectMapper()
.readValue(config, new TypeReference<Map<String, Object>>() {});
String name = (String) jsonContent.get("name");
if (name == null || name.length() < 1) {
String filename =
jsonFiles
.get(pipelineConfigs.indexOf(config))
.getFileName()
.toString();
name = filename.substring(0, filename.lastIndexOf('.'));
}
Map<String, String> configWithName = new HashMap<>();
configWithName.put("json", config);
configWithName.put("name", name);
pipelineConfigsWithNames.add(configWithName);
}
} catch (IOException e) {
log.error("Failed to load pipeline configs", e);
}
}
if (pipelineConfigsWithNames.isEmpty()) {
Map<String, String> configWithName = new HashMap<>();
configWithName.put("json", "");
configWithName.put("name", "No preloaded configs found");
pipelineConfigsWithNames.add(configWithName);
}
data.setPipelineConfigsWithNames(pipelineConfigsWithNames);
data.setPipelineConfigs(pipelineConfigs);
return ResponseEntity.ok(data);
}
@GetMapping("/sign")
@Operation(summary = "Get signature form data")
public ResponseEntity<SignData> getSignData() {
String username = "";
if (userService != null) {
username = userService.getCurrentUsername();
}
List<SignatureFile> signatures = signatureService.getAvailableSignatures(username);
List<FontResource> fonts = getFontNames();
SignData data = new SignData();
data.setSignatures(signatures);
data.setFonts(fonts);
return ResponseEntity.ok(data);
}
@GetMapping("/ocr-pdf")
@Operation(summary = "Get OCR PDF data")
public ResponseEntity<OcrData> getOcrPdfData() {
List<String> languages = getAvailableTesseractLanguages();
OcrData data = new OcrData();
data.setLanguages(languages);
return ResponseEntity.ok(data);
}
private List<String> getAvailableTesseractLanguages() {
String tessdataDir = applicationProperties.getSystem().getTessdataDir();
java.io.File[] files = new java.io.File(tessdataDir).listFiles();
if (files == null) {
return Collections.emptyList();
}
return Arrays.stream(files)
.filter(file -> file.getName().endsWith(".traineddata"))
.map(file -> file.getName().replace(".traineddata", ""))
.filter(lang -> !"osd".equalsIgnoreCase(lang))
.sorted()
.toList();
}
private List<FontResource> getFontNames() {
List<FontResource> fontNames = new ArrayList<>();
fontNames.addAll(getFontNamesFromLocation("classpath:static/fonts/*.woff2"));
fontNames.addAll(
getFontNamesFromLocation(
"file:"
+ InstallationPathConfig.getStaticPath()
+ "fonts"
+ java.io.File.separator
+ "*"));
return fontNames;
}
private List<FontResource> getFontNamesFromLocation(String locationPattern) {
try {
Resource[] resources =
GeneralUtils.getResourcesFromLocationPattern(locationPattern, resourceLoader);
return Arrays.stream(resources)
.map(
resource -> {
try {
String filename = resource.getFilename();
if (filename != null) {
int lastDotIndex = filename.lastIndexOf('.');
if (lastDotIndex != -1) {
String name = filename.substring(0, lastDotIndex);
String extension = filename.substring(lastDotIndex + 1);
return new FontResource(name, extension);
}
}
return null;
} catch (Exception e) {
throw ExceptionUtils.createRuntimeException(
"error.fontLoadingFailed",
"Error processing font file",
e);
}
})
.filter(Objects::nonNull)
.toList();
} catch (Exception e) {
throw ExceptionUtils.createRuntimeException(
"error.fontDirectoryReadFailed", "Failed to read font directory", e);
}
}
// Data classes
@Data
public static class HomeData {
private boolean showSurveyFromDocker;
}
@Data
public static class LicensesData {
private List<Dependency> dependencies;
}
@Data
public static class PipelineData {
private List<Map<String, String>> pipelineConfigsWithNames;
private List<String> pipelineConfigs;
}
@Data
public static class SignData {
private List<SignatureFile> signatures;
private List<FontResource> fonts;
}
@Data
public static class OcrData {
private List<String> languages;
}
@Data
public static class FontResource {
private String name;
private String extension;
private String type;
public FontResource(String name, String extension) {
this.name = name;
this.extension = extension;
this.type = getFormatFromExtension(extension);
}
private static String getFormatFromExtension(String extension) {
switch (extension) {
case "ttf":
return "truetype";
case "woff":
return "woff";
case "woff2":
return "woff2";
case "eot":
return "embedded-opentype";
case "svg":
return "svg";
default:
return "";
}
}
}
}
@@ -8,6 +8,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -19,7 +20,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.common.model.api.converters.EmlToPdfRequest;
import stirling.software.common.service.CustomPDFDocumentFactory;
@@ -40,7 +40,7 @@ public class ConvertEmlToPDF {
private final TempFileManager tempFileManager;
private final CustomHtmlSanitizer customHtmlSanitizer;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/eml/pdf")
@PostMapping(consumes = "multipart/form-data", value = "/eml/pdf")
@Operation(
summary = "Convert EML to PDF",
description =
@@ -2,6 +2,7 @@ package stirling.software.SPDF.controller.api.converters;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -12,7 +13,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.common.model.api.converters.HTMLToPdfRequest;
import stirling.software.common.service.CustomPDFDocumentFactory;
@@ -36,7 +36,7 @@ public class ConvertHtmlToPDF {
private final CustomHtmlSanitizer customHtmlSanitizer;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/html/pdf")
@PostMapping(consumes = "multipart/form-data", value = "/html/pdf")
@Operation(
summary = "Convert an HTML or ZIP (containing HTML and CSS) to PDF",
description =
@@ -19,6 +19,7 @@ import org.apache.pdfbox.rendering.ImageType;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -32,7 +33,6 @@ import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.converters.ConvertToImageRequest;
import stirling.software.SPDF.model.api.converters.ConvertToPdfRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.CheckProgramInstall;
import stirling.software.common.util.ExceptionUtils;
@@ -51,7 +51,7 @@ public class ConvertImgPDFController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/img")
@PostMapping(consumes = "multipart/form-data", value = "/pdf/img")
@Operation(
summary = "Convert PDF to image(s)",
description =
@@ -66,6 +66,7 @@ public class ConvertImgPDFController {
String colorType = request.getColorType();
int dpi = request.getDpi();
String pageNumbers = request.getPageNumbers();
boolean includeAnnotations = Boolean.TRUE.equals(request.getIncludeAnnotations());
Path tempFile = null;
Path tempOutputDir = null;
Path tempPdfPath = null;
@@ -101,7 +102,8 @@ public class ConvertImgPDFController {
colorTypeResult,
singleImage,
dpi,
filename);
filename,
includeAnnotations);
if (result == null || result.length == 0) {
log.error("resultant bytes for {} is null, error converting ", filename);
}
@@ -211,7 +213,7 @@ public class ConvertImgPDFController {
}
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/img/pdf")
@PostMapping(consumes = "multipart/form-data", value = "/img/pdf")
@Operation(
summary = "Convert images to a PDF file",
description =
@@ -12,6 +12,7 @@ import org.commonmark.renderer.html.AttributeProvider;
import org.commonmark.renderer.html.HtmlRenderer;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -22,7 +23,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.common.model.api.GeneralFile;
import stirling.software.common.service.CustomPDFDocumentFactory;
@@ -45,7 +45,7 @@ public class ConvertMarkdownToPdf {
private final CustomHtmlSanitizer customHtmlSanitizer;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
@PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
@Operation(
summary = "Convert a Markdown file to PDF",
description =
@@ -5,14 +5,16 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -22,8 +24,9 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.SPDF.config.EndpointConfiguration;
import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.common.model.api.GeneralFile;
import stirling.software.common.service.CustomPDFDocumentFactory;
@@ -36,59 +39,130 @@ import stirling.software.common.util.WebResponseUtils;
@Tag(name = "Convert", description = "Convert APIs")
@RequestMapping("/api/v1/convert")
@RequiredArgsConstructor
@Slf4j
public class ConvertOfficeController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
private final RuntimePathConfig runtimePathConfig;
private final CustomHtmlSanitizer customHtmlSanitizer;
private final EndpointConfiguration endpointConfiguration;
private boolean isUnoconvertAvailable() {
return endpointConfiguration.isGroupEnabled("Unoconvert")
|| endpointConfiguration.isGroupEnabled("Python");
}
public File convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException {
// Check for valid file extension
// Check for valid file extension and sanitize filename
String originalFilename = Filenames.toSimpleFileName(inputFile.getOriginalFilename());
if (originalFilename == null
|| !isValidFileExtension(FilenameUtils.getExtension(originalFilename))) {
throw new IllegalArgumentException("Invalid file extension");
if (originalFilename == null || originalFilename.isBlank()) {
throw new IllegalArgumentException("Missing original filename");
}
// Save the uploaded file to a temporary location
Path tempInputFile =
Files.createTempFile("input_", "." + FilenameUtils.getExtension(originalFilename));
// Check for valid file extension
String extension = FilenameUtils.getExtension(originalFilename);
if (extension == null || !isValidFileExtension(extension)) {
throw new IllegalArgumentException("Invalid file extension");
}
String extensionLower = extension.toLowerCase();
String baseName = FilenameUtils.getBaseName(originalFilename);
if (baseName == null || baseName.isBlank()) {
baseName = "input";
}
// create temporary working directory
Path workDir = Files.createTempDirectory("office2pdf_");
Path inputPath = workDir.resolve(baseName + "." + extensionLower);
Path outputPath = workDir.resolve(baseName + ".pdf");
// Check if the file is HTML and apply sanitization if needed
String fileExtension = FilenameUtils.getExtension(originalFilename).toLowerCase();
if ("html".equals(fileExtension) || "htm".equals(fileExtension)) {
if ("html".equals(extensionLower) || "htm".equals(extensionLower)) {
// Read and sanitize HTML content
String htmlContent = new String(inputFile.getBytes(), StandardCharsets.UTF_8);
String sanitizedHtml = customHtmlSanitizer.sanitize(htmlContent);
Files.write(tempInputFile, sanitizedHtml.getBytes(StandardCharsets.UTF_8));
Files.writeString(inputPath, sanitizedHtml, StandardCharsets.UTF_8);
} else {
inputFile.transferTo(tempInputFile);
// copy file content
Files.copy(inputFile.getInputStream(), inputPath, StandardCopyOption.REPLACE_EXISTING);
}
// Prepare the output file path
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
try {
// Run the LibreOffice command
List<String> command =
new ArrayList<>(
Arrays.asList(
runtimePathConfig.getUnoConvertPath(),
"--port",
"2003",
"--convert-to",
"pdf",
tempInputFile.toString(),
tempOutputFile.toString()));
ProcessExecutorResult returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE)
.runCommandWithOutputHandling(command);
ProcessExecutorResult result;
// Run Unoconvert command
if (isUnoconvertAvailable()) {
// Unoconvert: schreibe direkt in outputPath innerhalb des workDir
List<String> command = new ArrayList<>();
command.add(runtimePathConfig.getUnoConvertPath());
command.add("--port");
command.add("2003");
command.add("--convert-to");
command.add("pdf");
command.add(inputPath.toString());
command.add(outputPath.toString());
// Read the converted PDF file
return tempOutputFile.toFile();
result =
ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE)
.runCommandWithOutputHandling(command);
} // Run soffice command
else {
List<String> command = new ArrayList<>();
command.add("soffice");
command.add("--headless");
command.add("--nologo");
command.add("--convert-to");
command.add("pdf:writer_pdf_Export");
command.add("--outdir");
command.add(workDir.toString());
command.add(inputPath.toString());
result =
ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE)
.runCommandWithOutputHandling(command);
}
// Check the result
if (result == null) {
throw new IllegalStateException("Converter returned no result");
}
if (result.getRc() != 0) {
throw new IllegalStateException("Conversion failed (exit " + result.getRc() + ")");
}
if (!Files.exists(outputPath)) {
// Some LibreOffice versions may deviate with exotic names as a fallback, we try
// to find any .pdf in the workDir
try (var stream = Files.list(workDir)) {
Path fallback =
stream.filter(
p ->
p.getFileName()
.toString()
.toLowerCase()
.endsWith(".pdf"))
.findFirst()
.orElse(null);
if (fallback == null) {
throw new IllegalStateException("No PDF produced.");
}
// Move the found PDF to the expected outputPath
Files.move(fallback, outputPath, StandardCopyOption.REPLACE_EXISTING);
}
}
// Check if the output file is empty
if (Files.size(outputPath) == 0L) {
throw new IllegalStateException("Produced PDF is empty");
}
return outputPath.toFile();
} finally {
// Clean up the temporary files
if (tempInputFile != null) Files.deleteIfExists(tempInputFile);
try {
Files.deleteIfExists(inputPath);
} catch (IOException e) {
log.warn("Failed to delete temp input file: {}", inputPath, e);
}
}
}
@@ -97,7 +171,7 @@ public class ConvertOfficeController {
return fileExtension.matches(extensionPattern);
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/file/pdf")
@PostMapping(consumes = "multipart/form-data", value = "/file/pdf")
@Operation(
summary = "Convert a file to a PDF using LibreOffice",
description =
@@ -119,7 +193,9 @@ public class ConvertOfficeController {
.replaceFirst("[.][^.]+$", "")
+ "_convertedToPDF.pdf");
} finally {
if (file != null) file.delete();
if (file != null && file.getParent() != null) {
FileUtils.deleteDirectory(file.getParentFile());
}
}
}
}
@@ -2,6 +2,7 @@ package stirling.software.SPDF.controller.api.converters;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -9,7 +10,6 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.util.PDFToFile;
@@ -18,7 +18,7 @@ import stirling.software.common.util.PDFToFile;
@RequestMapping("/api/v1/convert")
public class ConvertPDFToHtml {
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/html")
@PostMapping(consumes = "multipart/form-data", value = "/pdf/html")
@Operation(
summary = "Convert PDF to HTML",
description =
@@ -7,6 +7,7 @@ import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -20,7 +21,6 @@ import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.model.api.converters.PdfToPresentationRequest;
import stirling.software.SPDF.model.api.converters.PdfToTextOrRTFRequest;
import stirling.software.SPDF.model.api.converters.PdfToWordRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.PDFToFile;
@@ -34,7 +34,7 @@ public class ConvertPDFToOffice {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/presentation")
@PostMapping(consumes = "multipart/form-data", value = "/pdf/presentation")
@Operation(
summary = "Convert PDF to Presentation format",
description =
@@ -49,7 +49,7 @@ public class ConvertPDFToOffice {
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "impress_pdf_import");
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/text")
@PostMapping(consumes = "multipart/form-data", value = "/pdf/text")
@Operation(
summary = "Convert PDF to Text or RTF format",
description =
@@ -77,7 +77,7 @@ public class ConvertPDFToOffice {
}
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/word")
@PostMapping(consumes = "multipart/form-data", value = "/pdf/word")
@Operation(
summary = "Convert PDF to Word document",
description =
@@ -91,7 +91,7 @@ public class ConvertPDFToOffice {
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "writer_pdf_import");
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/xml")
@PostMapping(consumes = "multipart/form-data", value = "/pdf/xml")
@Operation(
summary = "Convert PDF to XML",
description =
@@ -55,6 +55,7 @@ import org.apache.xmpbox.xml.XmpSerializer;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -66,7 +67,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.converters.PdfToPdfARequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.ProcessExecutor;
import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
@@ -78,7 +78,7 @@ import stirling.software.common.util.WebResponseUtils;
@Tag(name = "Convert", description = "Convert APIs")
public class ConvertPDFToPDFA {
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/pdfa")
@PostMapping(consumes = "multipart/form-data", value = "/pdf/pdfa")
@Operation(
summary = "Convert a PDF to a PDF/A",
description =
@@ -1,16 +1,21 @@
package stirling.software.SPDF.controller.api.converters;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -19,11 +24,9 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.converters.UrlToPdfRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.GeneralUtils;
import stirling.software.common.util.ProcessExecutor;
import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
@@ -40,30 +43,49 @@ public class ConvertWebsiteToPDF {
private final RuntimePathConfig runtimePathConfig;
private final ApplicationProperties applicationProperties;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/url/pdf")
@PostMapping(consumes = "multipart/form-data", value = "/url/pdf")
@Operation(
summary = "Convert a URL to a PDF",
description =
"This endpoint fetches content from a URL and converts it to a PDF format."
+ " Input:N/A Output:PDF Type:SISO")
public ResponseEntity<byte[]> urlToPdf(@ModelAttribute UrlToPdfRequest request)
public ResponseEntity<?> urlToPdf(@ModelAttribute UrlToPdfRequest request)
throws IOException, InterruptedException {
String URL = request.getUrlInput();
UriComponentsBuilder uriComponentsBuilder =
ServletUriComponentsBuilder.fromCurrentContextPath().path("/url-to-pdf");
URI location = null;
HttpStatus status = HttpStatus.SEE_OTHER;
if (!applicationProperties.getSystem().getEnableUrlToPDF()) {
throw ExceptionUtils.createIllegalArgumentException(
"error.endpointDisabled", "This endpoint has been disabled by the admin");
}
location =
uriComponentsBuilder
.queryParam("error", "error.endpointDisabled")
.build()
.toUri();
} else
// Validate the URL format
if (!URL.matches("^https?://.*") || !GeneralUtils.isValidURL(URL)) {
throw ExceptionUtils.createInvalidArgumentException(
"URL", "provided format is invalid");
}
location =
uriComponentsBuilder
.queryParam("error", "error.invalidUrlFormat")
.build()
.toUri();
} else
// validate the URL is reachable
if (!GeneralUtils.isURLReachable(URL)) {
throw ExceptionUtils.createIllegalArgumentException(
"error.urlNotReachable", "URL is not reachable, please provide a valid URL");
location =
uriComponentsBuilder
.queryParam("error", "error.urlNotReachable")
.build()
.toUri();
}
if (location != null) {
log.info("Redirecting to: {}", location.toString());
return ResponseEntity.status(status).location(location).build();
}
Path tempOutputFile = null;
@@ -18,6 +18,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -29,7 +30,6 @@ import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.PDFWithPageNums;
import stirling.software.SPDF.pdf.FlexibleCSVWriter;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import technology.tabula.ObjectExtractor;
@@ -46,7 +46,7 @@ public class ExtractCSVController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/pdf/csv", consumes = "multipart/form-data")
@PostMapping(value = "/pdf/csv", consumes = "multipart/form-data")
@Operation(
summary = "Extracts a CSV document from a PDF",
description =

Some files were not shown because too many files have changed in this diff Show More