Compare commits

...

104 Commits

Author SHA1 Message Date
Julien Neuhart
f54f78d186 chore(build): use Chromium for all arch 2025-08-18 21:08:14 +02:00
Julien Neuhart
97ec4949d7 chore(deps): bump debian from 12-slim to 13-slim 2025-08-18 20:55:19 +02:00
dependabot[bot]
f08b9d389b chore(deps): bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 06:58:48 +02:00
Julien Neuhart
4fc94cae24 chore(deps): npm update 2025-08-15 17:23:09 +02:00
Julien Neuhart
8cab8230e6 chore(deps): update noto-color-emoji to v2.048 2025-08-15 17:22:18 +02:00
Julien Neuhart
b7afa49c9f chore(deps): update pdfcpu to v0.11.0 2025-08-15 17:21:10 +02:00
Julien Neuhart
e0b5ccb41d chore(go): update to 1.25 2025-08-15 17:15:01 +02:00
Julien Neuhart
fb63ffb919 ci(lint): update golangci-lint 2025-08-15 17:14:44 +02:00
Julien Neuhart
cb98b0c937 feat(misc): add --gotenberg-hide-banner flag 2025-08-15 07:36:47 +02:00
Julien Neuhart
bee56cfd99 fix(ci): add missing outputs for AWS Lambda tags 2025-08-15 07:24:12 +02:00
Julien Neuhart
9e130614ce fix(ci): ignore empty tags in push step - second attempt 2025-08-14 22:03:53 +02:00
Julien Neuhart
2f487d2e83 fix(ci): ignore empty tags in push step 2025-08-14 21:37:41 +02:00
Julien Neuhart
1ff4b3a4fc fix(ci): add missing AWS Lambda tags to push step 2025-08-14 21:12:46 +02:00
Julien Neuhart
e86d38c52c feat(build): add default configuration for Cloud Run variant 2025-08-14 20:46:43 +02:00
Julien Neuhart
d371ae8ceb chore(build): add missing GOTENBERG_BUILD_DEBUG_DATA configuration for AWS Lambda 2025-08-14 20:46:09 +02:00
Julien Neuhart
a9d10b2bf3 fix(build): missing args for AWS Lambda Dockerfile 2025-08-14 20:44:03 +02:00
Julien Neuhart
d6ffd193d3 ci(build): #540 add AWS Lambda support 2025-08-14 20:40:38 +02:00
Julien Neuhart
2635213947 feat(build): #540 add AWS Lambda support 2025-08-14 20:39:53 +02:00
Julien Neuhart
d496cbfb53 fix(sort): better sorting algorithm - fixes #1287 2025-08-12 21:21:03 +02:00
Julien Neuhart
db8f0ad9ee fix(chromium): hypen-data now work everytime 2025-08-12 20:54:53 +02:00
dependabot[bot]
8d795a4317 chore(deps): bump golang.org/x/net from 0.42.0 to 0.43.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.42.0 to 0.43.0.
- [Commits](https://github.com/golang/net/compare/v0.42.0...v0.43.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.43.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 09:46:29 +02:00
dependabot[bot]
1a9ae456dd chore(deps): bump github.com/chromedp/chromedp from 0.14.0 to 0.14.1
Bumps [github.com/chromedp/chromedp](https://github.com/chromedp/chromedp) from 0.14.0 to 0.14.1.
- [Release notes](https://github.com/chromedp/chromedp/releases)
- [Commits](https://github.com/chromedp/chromedp/compare/v0.14.0...v0.14.1)

---
updated-dependencies:
- dependency-name: github.com/chromedp/chromedp
  dependency-version: 0.14.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 09:46:18 +02:00
dependabot[bot]
4e9d7a3f8c chore(deps): bump github.com/docker/go-connections from 0.5.0 to 0.6.0
Bumps [github.com/docker/go-connections](https://github.com/docker/go-connections) from 0.5.0 to 0.6.0.
- [Commits](https://github.com/docker/go-connections/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: github.com/docker/go-connections
  dependency-version: 0.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 09:02:09 +02:00
dependabot[bot]
087967befb chore(deps): bump golang.org/x/term from 0.33.0 to 0.34.0
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.33.0 to 0.34.0.
- [Commits](https://github.com/golang/term/compare/v0.33.0...v0.34.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-version: 0.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 08:59:00 +02:00
Julien Neuhart
02ad6c7834 feat(webhook): switch to --webhook-enable-sync-mode flag instead of header 2025-08-09 16:17:27 +02:00
Yash Narwal
fc11f557fa feat(webhook) add support for sync upload with webhook url (#1233)
* Add support for having sync upload with webhook url

* Update tests

* Make SendOutputFileParams interface private

* Make interface params private
2025-08-08 09:25:46 +02:00
RJ Sampson
f299f3ed20 fix(chromium): Enable GPU support
Chromium 139 is set to deprecate the Swiftshader backend entirely:

https://chromestatus.com/feature/5166674414927872

And 138 doesn't provide fallback without explicitly enabling it,
breaking functionality such as WebGL in Gotenberg

Re-enable GPU support to work around this

Signed-off-by: RJ Sampson <rj.sampson@chainguard.dev>
2025-08-06 10:31:00 +02:00
Julien Neuhart
94c831cd05 fix(integration): failing scenarios 2025-08-03 18:49:14 +02:00
Julien Neuhart
53b4c70e4b chore: prettify 2025-08-03 18:19:43 +02:00
Julien Neuhart
6ff5109b00 fix(integration): non-working scenarios because of a remote service down 2025-08-03 18:02:35 +02:00
dependabot[bot]
339afe614c chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.3.2+incompatible to 28.3.3+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.3.2...v28.3.3)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.3.3+incompatible
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-30 09:51:05 +02:00
dependabot[bot]
911fdd3067 chore(deps): bump github.com/testcontainers/testcontainers-go
---
updated-dependencies:
- dependency-name: github.com/testcontainers/testcontainers-go
  dependency-version: 0.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 09:02:03 +02:00
dependabot[bot]
588e27e6d1 chore(deps): bump github.com/cucumber/godog from 0.15.0 to 0.15.1
Bumps [github.com/cucumber/godog](https://github.com/cucumber/godog) from 0.15.0 to 0.15.1.
- [Release notes](https://github.com/cucumber/godog/releases)
- [Changelog](https://github.com/cucumber/godog/blob/main/CHANGELOG.md)
- [Commits](https://github.com/cucumber/godog/compare/v0.15.0...v0.15.1)

---
updated-dependencies:
- dependency-name: github.com/cucumber/godog
  dependency-version: 0.15.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 09:01:53 +02:00
Andrea
3a71032d62 tests(integration): use same targeted platform for integration-tools image (#1275)
* Use same targeted platform integration-tools image @ integration tests

* run make fmt
2025-07-16 11:30:41 +02:00
dependabot[bot]
59a091e7dc chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.3.1+incompatible to 28.3.2+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.3.1...v28.3.2)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.3.2+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-15 11:19:21 +02:00
dependabot[bot]
0e250a99ed chore(deps): bump golang.org/x/net from 0.41.0 to 0.42.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.41.0 to 0.42.0.
- [Commits](https://github.com/golang/net/compare/v0.41.0...v0.42.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-15 11:13:41 +02:00
dependabot[bot]
f73b72753f chore(deps): bump github.com/docker/docker
---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.3.1+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 08:57:27 +02:00
dependabot[bot]
00a85b0d90 chore(deps): bump github.com/shirou/gopsutil/v4 from 4.25.5 to 4.25.6
---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.25.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 08:57:17 +02:00
dependabot[bot]
e79d7e6fb5 chore(deps-dev): bump prettier-plugin-sh from 0.17.4 to 0.18.0
Bumps [prettier-plugin-sh](https://github.com/un-ts/prettier) from 0.17.4 to 0.18.0.
- [Release notes](https://github.com/un-ts/prettier/releases)
- [Changelog](https://github.com/un-ts/prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/un-ts/prettier/compare/prettier-plugin-sh@0.17.4...prettier-plugin-sh@0.18.0)

---
updated-dependencies:
- dependency-name: prettier-plugin-sh
  dependency-version: 0.18.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 10:46:30 +02:00
dependabot[bot]
ef745dc378 chore(deps-dev): bump prettier from 3.6.0 to 3.6.2
Bumps [prettier](https://github.com/prettier/prettier) from 3.6.0 to 3.6.2.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.6.0...3.6.2)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.6.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 10:46:03 +02:00
dependabot[bot]
ac5dfb7ff0 chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.2.2+incompatible to 28.3.0+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.2.2...v28.3.0)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.3.0+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 10:45:45 +02:00
dependabot[bot]
51b0841171 chore(deps): bump github.com/mholt/archives from 0.1.2 to 0.1.3
Bumps [github.com/mholt/archives](https://github.com/mholt/archives) from 0.1.2 to 0.1.3.
- [Release notes](https://github.com/mholt/archives/releases)
- [Commits](https://github.com/mholt/archives/compare/v0.1.2...v0.1.3)

---
updated-dependencies:
- dependency-name: github.com/mholt/archives
  dependency-version: 0.1.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 10:45:34 +02:00
dependabot[bot]
57264da21b chore(deps): bump github.com/alexliesenfeld/health from 0.8.0 to 0.8.1
Bumps [github.com/alexliesenfeld/health](https://github.com/alexliesenfeld/health) from 0.8.0 to 0.8.1.
- [Release notes](https://github.com/alexliesenfeld/health/releases)
- [Changelog](https://github.com/alexliesenfeld/health/blob/main/CHANGELOG.md)
- [Commits](https://github.com/alexliesenfeld/health/compare/v0.8.0...v0.8.1)

---
updated-dependencies:
- dependency-name: github.com/alexliesenfeld/health
  dependency-version: 0.8.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 06:27:51 +02:00
dependabot[bot]
16f740b318 chore(deps): bump github.com/hashicorp/go-retryablehttp
Bumps [github.com/hashicorp/go-retryablehttp](https://github.com/hashicorp/go-retryablehttp) from 0.7.7 to 0.7.8.
- [Changelog](https://github.com/hashicorp/go-retryablehttp/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/go-retryablehttp/compare/v0.7.7...v0.7.8)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/go-retryablehttp
  dependency-version: 0.7.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 06:27:38 +02:00
dependabot[bot]
2ba70141cc chore(deps): bump github.com/chromedp/chromedp from 0.13.6 to 0.13.7
Bumps [github.com/chromedp/chromedp](https://github.com/chromedp/chromedp) from 0.13.6 to 0.13.7.
- [Release notes](https://github.com/chromedp/chromedp/releases)
- [Commits](https://github.com/chromedp/chromedp/compare/v0.13.6...v0.13.7)

---
updated-dependencies:
- dependency-name: github.com/chromedp/chromedp
  dependency-version: 0.13.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 06:27:27 +02:00
dependabot[bot]
e945329d91 chore(deps-dev): bump prettier from 3.5.3 to 3.6.0
Bumps [prettier](https://github.com/prettier/prettier) from 3.5.3 to 3.6.0.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.5.3...3.6.0)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 06:27:13 +02:00
dependabot[bot]
ffeb4703fd chore(deps): bump golang.org/x/net from 0.40.0 to 0.41.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.40.0 to 0.41.0.
- [Commits](https://github.com/golang/net/compare/v0.40.0...v0.41.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.41.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 10:08:55 +02:00
dependabot[bot]
fcf41187fa chore(deps): bump golang.org/x/text from 0.25.0 to 0.26.0
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.25.0 to 0.26.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.25.0...v0.26.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-version: 0.26.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 10:06:42 +02:00
dependabot[bot]
f0fc704efc chore(deps): bump golang.org/x/sync from 0.14.0 to 0.15.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.14.0 to 0.15.0.
- [Commits](https://github.com/golang/sync/compare/v0.14.0...v0.15.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-version: 0.15.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 10:06:30 +02:00
Julien Neuhart
aa58615650 fix(api): outpout filename as path - fixes #1227 2025-06-06 15:14:06 +00:00
Julien Neuhart
b0a84bcbf7 chore(integration): prettify 2025-06-02 11:45:44 +02:00
Julien Neuhart
cf2d413a28 test(integration): comment scenario that is not happening anymore on amd architectures 2025-06-02 11:27:25 +02:00
dependabot[bot]
9226b78b0c chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.1.1+incompatible to 28.2.2+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.1.1...v28.2.2)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.2.2+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 07:09:19 +02:00
dependabot[bot]
a635fd8a7b chore(deps): bump github.com/shirou/gopsutil/v4 from 4.25.4 to 4.25.5
Bumps [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) from 4.25.4 to 4.25.5.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.25.4...v4.25.5)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.25.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 07:06:58 +02:00
Julien Neuhart
6f714277f7 docs(README): remove Zolsec from sponsors 2025-05-28 15:25:04 +02:00
dependabot[bot]
4aff4982b0 chore(deps): bump github.com/labstack/echo/v4 from 4.13.3 to 4.13.4
Bumps [github.com/labstack/echo/v4](https://github.com/labstack/echo) from 4.13.3 to 4.13.4.
- [Release notes](https://github.com/labstack/echo/releases)
- [Changelog](https://github.com/labstack/echo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/labstack/echo/compare/v4.13.3...v4.13.4)

---
updated-dependencies:
- dependency-name: github.com/labstack/echo/v4
  dependency-version: 4.13.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-26 07:11:51 +02:00
Julien Neuhart
8634989497 fix(Dockerfile): typo 2025-05-22 09:41:41 +02:00
Julien Neuhart
a50e60b2a0 fix(Dockerfile): remove fonts-dejavu-extra as the package is already packaged in fonts-dejavu 2025-05-22 09:41:07 +02:00
Julien Neuhart
8875f4dfc4 ci: fix needs entries in merge_clean_snapshot_tags step 2025-05-21 00:34:56 +02:00
Julien Neuhart
61c8217ed5 feat(Dockerfile): support for arbitrary user ids - closes #1049 2025-05-21 00:34:56 +02:00
Julien Neuhart
f75912033e feat(chromium): split filenames can be controlled with the Gotenberg-Output-Filename header - closes #1130 2025-05-20 14:14:05 +02:00
Julien Neuhart
1d8630810b fix(godoc): typo 2025-05-20 11:50:18 +02:00
Julien Neuhart
ce155fb43e feat(chromium): add generateTaggedPdf to form fields - closes #1210 2025-05-20 11:49:10 +02:00
dependabot[bot]
67ebe17fcb chore(deps): bump github.com/mholt/archives from 0.1.1 to 0.1.2
Bumps [github.com/mholt/archives](https://github.com/mholt/archives) from 0.1.1 to 0.1.2.
- [Release notes](https://github.com/mholt/archives/releases)
- [Commits](https://github.com/mholt/archives/compare/v0.1.1...v0.1.2)

---
updated-dependencies:
- dependency-name: github.com/mholt/archives
  dependency-version: 0.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 09:09:25 +02:00
Julien Neuhart
f13a6c0a3b Revert "fix(libreoffice): correct values for CreateDate, MetadataDate, and ModifyDate metadata entries - fixes #1193"
This reverts commit e662f5ce0b.
2025-05-18 14:15:22 +02:00
Julien Neuhart
e1870429b9 Revert "test(integration): fix rules failed toleration"
This reverts commit de1b887d29.
2025-05-18 14:15:12 +02:00
Hector Zarate
5aa1cd7f40 feat(Dockerfile): pin versions of dependencies (#1190)
* Pin versions of dependencies

* no need to override default values in github build action

* unpin curl,gnupg,tiny,python3,default-jre-headless

* Revert "unpin curl,gnupg,tiny,python3,default-jre-headless"

This reverts commit 95b0250700.

* remove pin from Libreoffice

* Update build/Dockerfile

Co-authored-by: Julien Neuhart <neuhart.julien@gmail.com>

---------

Co-authored-by: Julien Neuhart <neuhart.julien@gmail.com>
2025-05-18 14:08:11 +02:00
Julien Neuhart
de1b887d29 test(integration): fix rules failed toleration 2025-05-15 14:23:31 +02:00
Julien Neuhart
e662f5ce0b fix(libreoffice): correct values for CreateDate, MetadataDate, and ModifyDate metadata entries - fixes #1193 2025-05-15 10:38:22 +02:00
Julien Neuhart
790b69a32e test(integration): fix typo 2025-05-15 10:16:57 +02:00
Julien Neuhart
9aaab97d6a fix(pdfengines): read metadata better webhook error - fixes #1148 2025-05-15 09:22:52 +02:00
Julien Neuhart
66317197b6 fix: graceful shutdown with asynchronous processes - fixes #1022 2025-05-14 15:27:14 +02:00
Julien Neuhart
91757335ac ci: make it work for forks too 2025-05-14 09:37:42 +02:00
Julien Neuhart
be3145aae9 chore(libreoffice): switch to env var for handling non-basic latin characters in filenames 2025-05-13 16:10:14 +02:00
Julien Neuhart
79425af848 feat(Dockerfile): use jlink to switch to a lightweight JRE 2025-05-13 16:06:59 +02:00
Julien Neuhart
45b47a1071 feat(Dockerfile): use upx-ucl to reduce Go binaries size 2025-05-13 16:06:59 +02:00
Julien Neuhart
4b30567c39 feat(chromium): close page after conversion 2025-05-12 09:35:10 +02:00
dependabot[bot]
1ed33a7400 chore(deps): bump golang.org/x/net from 0.39.0 to 0.40.0 (#1204)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.39.0 to 0.40.0.
- [Commits](https://github.com/golang/net/compare/v0.39.0...v0.40.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.40.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-12 08:56:09 +02:00
dependabot[bot]
ca1d11006c chore(deps-dev): bump prettier-plugin-sh from 0.17.2 to 0.17.4 (#1205)
Bumps [prettier-plugin-sh](https://github.com/un-ts/prettier) from 0.17.2 to 0.17.4.
- [Release notes](https://github.com/un-ts/prettier/releases)
- [Changelog](https://github.com/un-ts/prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/un-ts/prettier/compare/prettier-plugin-sh@0.17.2...prettier-plugin-sh@0.17.4)

---
updated-dependencies:
- dependency-name: prettier-plugin-sh
  dependency-version: 0.17.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-12 08:56:00 +02:00
teng
71f1f3dd22 feat(chromium): change sort of wait delay action and wait expression action (#1186)
eg: scroll screen to load all lazy image.
2025-05-06 10:26:46 +02:00
dependabot[bot]
64add9a542 chore(deps-dev): bump prettier-plugin-sh from 0.15.0 to 0.17.2
Bumps [prettier-plugin-sh](https://github.com/un-ts/prettier) from 0.15.0 to 0.17.2.
- [Release notes](https://github.com/un-ts/prettier/releases)
- [Changelog](https://github.com/un-ts/prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/un-ts/prettier/compare/prettier-plugin-sh@0.15.0...prettier-plugin-sh@0.17.2)

---
updated-dependencies:
- dependency-name: prettier-plugin-sh
  dependency-version: 0.17.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-05 19:40:13 +02:00
dependabot[bot]
a7c02438e4 chore(deps-dev): bump prettier from 3.5.2 to 3.5.3
Bumps [prettier](https://github.com/prettier/prettier) from 3.5.2 to 3.5.3.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.5.2...3.5.3)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.5.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-05 19:39:58 +02:00
dependabot[bot]
910af7a44c chore(deps): bump golang.org/x/sync from 0.13.0 to 0.14.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.13.0 to 0.14.0.
- [Commits](https://github.com/golang/sync/compare/v0.13.0...v0.14.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-version: 0.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-05 19:21:55 +02:00
dependabot[bot]
05f9ac3745 chore(deps-dev): bump prettier-plugin-gherkin from 3.1.1 to 3.1.2
Bumps [prettier-plugin-gherkin](https://github.com/mapado/prettier-plugin-gherkin) from 3.1.1 to 3.1.2.
- [Release notes](https://github.com/mapado/prettier-plugin-gherkin/releases)
- [Changelog](https://github.com/mapado/prettier-plugin-gherkin/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mapado/prettier-plugin-gherkin/compare/v3.1.1...v3.1.2)

---
updated-dependencies:
- dependency-name: prettier-plugin-gherkin
  dependency-version: 3.1.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-05 19:21:35 +02:00
dependabot[bot]
5c43eefe46 chore(deps): bump golangci/golangci-lint-action from 7 to 8
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 7 to 8.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v7...v8)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-05 15:52:15 +02:00
Julien Neuhart
b63f4c53d2 ci(lint): update golangci-lint version 2025-05-05 15:49:24 +02:00
Julien Neuhart
3d652bc829 ci(dependabot): add npm 2025-05-05 15:48:52 +02:00
dependabot[bot]
c78ef8771d chore(deps): bump github.com/shirou/gopsutil/v4 from 4.25.3 to 4.25.4
Bumps [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil) from 4.25.3 to 4.25.4.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v4.25.3...v4.25.4)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v4
  dependency-version: 4.25.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-05 08:40:41 +02:00
dependabot[bot]
9a38f16219 chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.0.4+incompatible to 28.1.1+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.0.4...v28.1.1)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.1.1+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-26 13:49:14 +02:00
dependabot[bot]
e5363205a7 chore(deps): bump github.com/testcontainers/testcontainers-go
Bumps [github.com/testcontainers/testcontainers-go](https://github.com/testcontainers/testcontainers-go) from 0.36.0 to 0.37.0.
- [Release notes](https://github.com/testcontainers/testcontainers-go/releases)
- [Commits](https://github.com/testcontainers/testcontainers-go/compare/v0.36.0...v0.37.0)

---
updated-dependencies:
- dependency-name: github.com/testcontainers/testcontainers-go
  dependency-version: 0.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-26 13:48:41 +02:00
Hector Zarate
088b3274f2 feat(dep): add dependabot for mod and docker files (#1179)
* add dependabot for mod and docker files

* lint dependabot file
2025-04-26 13:07:51 +02:00
Julien Neuhart
fabe323e34 fix(chromium): add --no-zygote and --disable-dev-shm-usage flags - fixes #1177 2025-04-17 11:28:17 +02:00
Julien Neuhart
a731bf034e chore(deps): update Go dependencies 2025-04-17 11:27:47 +02:00
Julien Neuhart
3cbf772acf docs(godoc): fix a bunch of typos 2025-04-17 11:15:52 +02:00
Julien Neuhart
9701f88ae3 fix(pdfcpu): use custom sort to retrieve the splitted PDFs 2025-04-12 19:40:16 +02:00
Julien Neuhart
7ca1d118a1 chore(deps): update Go dependencies 2025-04-12 17:37:15 +02:00
Julien Neuhart
a7dfa21cbf fix(pdfengines): correct merge order - fixes #1168 2025-04-12 17:25:39 +02:00
Julien Neuhart
ab81444773 fix(Makefile): add double-quote to new flag 2025-04-12 17:24:23 +02:00
Julien Neuhart
02c4343dfd fix(test): missing env var for debug 2025-04-10 16:28:15 +02:00
Hector Zarate
1bfe86738f feat(debug): only build debug data when flag is true (#1167)
* only build debug info when log level is debug

* introduce new flag 'gotenberg-build-debug-data'

* add gotenberg-build-debug-data flag to Makefile

* add new integration test for gotenberg-build-debug-data flag

* update GET /debug (Enabled) test with gotenberg-build-debug-data flag

* reorder GOTENBERG_BUILD_DEBUG_DATA in Makefile

* reorder Build Debug Data Disabled test scenario

---------

Co-authored-by: Hector Zarate <hector@Hectors-MacBook-Pro.local>
2025-04-10 13:30:24 +02:00
Julien Neuhart
7fe0e05050 test(webhook): add integration testing for the webhook feature - testing the custom Content-Disposition header from #1165 2025-04-08 18:51:51 +02:00
stephentgrammer
10588efe25 fix(webhook): content-disposition header (#1164)
* fix(webhook): pass content-disposition header through and fix spelling of attachment on default

* code review

Co-authored-by: Julien Neuhart <neuhart.julien@gmail.com>

* formatting

---------

Co-authored-by: Julien Neuhart <neuhart.julien@gmail.com>
2025-04-04 03:04:14 +02:00
Julien Neuhart
bf4607d368 chore(.gitignore): remove coverage entries [skip ci] 2025-04-02 15:04:52 +02:00
Julien Neuhart
45f04ae8d4 fix(chromium): printBackground now works as expected and PDF are not tagged anymore - fixes #1154 and fixes #1058 2025-04-02 14:07:15 +02:00
130 changed files with 1504 additions and 692 deletions

10
.env
View File

@@ -1,13 +1,7 @@
GOLANG_VERSION=1.24
GOTENBERG_VERSION=snapshot
DOCKER_REGISTRY=gotenberg
DOCKER_REPOSITORY=gotenberg
GOTENBERG_VERSION=snapshot
GOTENBERG_USER_GID=1001
GOTENBERG_USER_UID=1001
NOTO_COLOR_EMOJI_VERSION=v2.047 # See https://github.com/googlefonts/noto-emoji/releases.
PDFTK_VERSION=v3.3.3 # See https://gitlab.com/pdftk-java/pdftk/-/releases - Binary package.
PDFCPU_VERSION=v0.8.1 # See https://github.com/pdfcpu/pdfcpu/releases.
GOTENBERG_VERSION=snapshot
DOCKERFILE=build/Dockerfile
DOCKERFILE_CLOUDRUN=build/Dockerfile.cloudrun
DOCKERFILE_AWS_LAMBDA=build/Dockerfile.aws-lambda
DOCKER_BUILD_CONTEXT='.'

View File

@@ -34,6 +34,9 @@ outputs:
tags_cloud_run:
description: Comma separated list of Cloud Run tags (linux/amd64 only)
value: ${{ steps.build.outputs.tags_cloud_run }}
tags_aws_lambda:
description: Comma separated list of AWS Lambda tags (linux/amd64 and linux/arm64 only)
value: ${{ steps.build.outputs.tags_aws_lambda }}
runs:
using: composite
@@ -48,6 +51,7 @@ runs:
uses: actions/checkout@v4
- name: Log in to Docker Hub
if: inputs.docker_hub_username != ''
uses: docker/login-action@v3
with:
username: ${{ inputs.docker_hub_username }}
@@ -64,7 +68,7 @@ runs:
--dry-run "${{ inputs.dry_run }}"
- name: Run integration tests
if: ${{ inputs.skip_integrations_tests != 'true' }}
if: inputs.skip_integrations_tests != 'true'
shell: bash
run: |
.github/actions/build-test-push/test.sh \
@@ -74,10 +78,11 @@ runs:
--dry-run "${{ inputs.dry_run }}"
- name: Push
if: inputs.docker_hub_username != ''
shell: bash
run: |
.github/actions/build-test-push/push.sh \
--tags "${{ steps.build.outputs.tags }},${{ steps.build.outputs.tags_cloud_run }}" \
--tags "${{ steps.build.outputs.tags }},${{ steps.build.outputs.tags_cloud_run }},${{ steps.build.outputs.tags_aws_lambda }}" \
--dry-run "${{ inputs.dry_run }}"
- name: Outputs
@@ -85,3 +90,4 @@ runs:
run: |
echo "tags=${{ steps.build.outputs.tags }}"
echo "tags_cloud_run=${{ steps.build.outputs.tags_cloud_run }}"
echo "tags_aws_lambda=${{ steps.build.outputs.tags_aws_lambda }}"

View File

@@ -56,6 +56,7 @@ fi
# Build tags arrays.
tags=()
tags_cloud_run=()
tags_aws_lambda=()
IFS='/' read -ra arch <<< "$platform"
IFS='.' read -ra semver <<< "$version"
@@ -79,6 +80,13 @@ if [ "${#semver[@]}" -eq 3 ]; then
tags_cloud_run+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor-cloudrun")
tags_cloud_run+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor.$patch-cloudrun")
fi
if [ "$platform" = "linux/amd64" ] || [ "$platform" = "linux/arm64" ]; then
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:latest-aws-lambda-${arch[1]}")
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major-aws-lambda-${arch[1]}")
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor-aws-lambda-${arch[1]}")
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor.$patch-aws-lambda-${arch[1]}")
fi
else
echo
echo "Non-semver version detected, fallback to $version"
@@ -87,10 +95,15 @@ else
if [ "$platform" = "linux/amd64" ]; then
tags_cloud_run+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$version-cloudrun")
fi
if [ "$platform" = "linux/amd64" ] || [ "$platform" = "linux/arm64" ]; then
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$version-aws-lambda-${arch[1]}")
fi
fi
tags_flags=()
tags_cloud_run_flags=()
tags_aws_lambda_flags=()
echo "Will use the following tags:"
for tag in "${tags[@]}"; do
@@ -101,6 +114,10 @@ for tag in "${tags_cloud_run[@]}"; do
tags_cloud_run_flags+=("-t" "$tag")
echo "- $tag"
done
for tag in "${tags_aws_lambda[@]}"; do
tags_aws_lambda_flags+=("-t" "$tag")
echo "- $tag"
done
echo
# Build images.
@@ -129,13 +146,7 @@ join() {
no_arch_tag="$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$version"
cmd="docker buildx build \
--build-arg GOLANG_VERSION=$GOLANG_VERSION \
--build-arg GOTENBERG_VERSION=$version \
--build-arg GOTENBERG_USER_GID=$GOTENBERG_USER_GID \
--build-arg GOTENBERG_USER_UID=$GOTENBERG_USER_UID \
--build-arg NOTO_COLOR_EMOJI_VERSION=$NOTO_COLOR_EMOJI_VERSION \
--build-arg PDFTK_VERSION=$PDFTK_VERSION \
--build-arg PDFCPU_VERSION=$PDFCPU_VERSION \
--platform $platform \
--load \
${tags_flags[*]} \
@@ -144,24 +155,30 @@ cmd="docker buildx build \
"
run_cmd "$cmd"
if [ "$platform" != "linux/amd64" ]; then
echo "⚠️ Skip Cloud Run variant(s)"
echo "✅ Done!"
echo "tags=$(join "," "${tags[@]}")" >> "$GITHUB_OUTPUT"
echo "tags_cloud_run=$(join "," "${tags_cloud_run[@]}")" >> "$GITHUB_OUTPUT"
exit 0
if [ "$platform" = "linux/amd64" ]; then
cmd="docker build \
--build-arg DOCKER_REGISTRY=$DOCKER_REGISTRY \
--build-arg DOCKER_REPOSITORY=$DOCKER_REPOSITORY \
--build-arg GOTENBERG_VERSION=$version \
${tags_cloud_run_flags[*]} \
-f $DOCKERFILE_CLOUDRUN $DOCKER_BUILD_CONTEXT
"
run_cmd "$cmd"
fi
cmd="docker build \
--build-arg DOCKER_REGISTRY=$DOCKER_REGISTRY \
--build-arg DOCKER_REPOSITORY=$DOCKER_REPOSITORY \
--build-arg GOTENBERG_VERSION=$version \
${tags_cloud_run_flags[*]} \
-f $DOCKERFILE_CLOUDRUN $DOCKER_BUILD_CONTEXT
"
run_cmd "$cmd"
if [ "$platform" = "linux/amd64" ] || [ "$platform" = "linux/arm64" ]; then
cmd="docker build \
--build-arg DOCKER_REGISTRY=$DOCKER_REGISTRY \
--build-arg DOCKER_REPOSITORY=$DOCKER_REPOSITORY \
--build-arg GOTENBERG_VERSION=$version \
${tags_aws_lambda_flags[*]} \
-f $DOCKERFILE_AWS_LAMBDA $DOCKER_BUILD_CONTEXT
"
run_cmd "$cmd"
fi
echo "✅ Done!"
echo "tags=$(join "," "${tags[@]}")" >> "$GITHUB_OUTPUT"
echo "tags_cloud_run=$(join "," "${tags_cloud_run[@]}")" >> "$GITHUB_OUTPUT"
echo "tags_aws_lambda=$(join "," "${tags_aws_lambda[@]}")" >> "$GITHUB_OUTPUT"
exit 0

View File

@@ -32,7 +32,13 @@ echo "Push tag(s) 📦"
echo
echo "Tag(s) to push:"
IFS=',' read -ra tags_to_push <<< "$tags"
IFS=',' read -ra tmp_tags_to_push <<< "$tags"
tags_to_push=()
for tag in "${tmp_tags_to_push[@]}"; do
[ -n "$tag" ] && tags_to_push+=("$tag")
done
for tag in "${tags_to_push[@]}"; do
echo "- $tag"
done

View File

@@ -40,6 +40,7 @@ IFS=',' read -ra tags_to_delete <<< "$tags"
if [ -n "$snapshot_version" ]; then
tags_to_delete+=("$DOCKER_REGISTRY/snapshot:$snapshot_version")
tags_to_delete+=("$DOCKER_REGISTRY/snapshot:$snapshot_version-cloudrun")
tags_to_delete+=("$DOCKER_REGISTRY/snapshot:$snapshot_version-aws-lambda")
fi
echo "Will delete the following tag(s):"

View File

@@ -1,7 +1,18 @@
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "docker"
directory: "/build"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"

View File

@@ -14,9 +14,10 @@ jobs:
outputs:
tags: ${{ steps.build_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Build and push
id: build_push
@@ -33,10 +34,9 @@ jobs:
runs-on: ubuntu-latest
outputs:
tags: ${{ steps.build_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Build and push
id: build_push
@@ -54,9 +54,10 @@ jobs:
outputs:
tags: ${{ steps.build_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Build and push
id: build_push
@@ -74,9 +75,10 @@ jobs:
outputs:
tags: ${{ steps.build_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Build and push
id: build_push
@@ -98,7 +100,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Merge
uses: ./.github/actions/merge
@@ -108,9 +110,17 @@ jobs:
tags: "${{ needs.release_amd64.outputs.tags }},${{ needs.release_386.outputs.tags }},${{ needs.release_arm64.outputs.tags }},${{ needs.release_arm_v7.outputs.tags }}"
alternate_registry: thecodingmachine
- name: Merge AWS Lambda
uses: ./.github/actions/merge
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.release_amd64.outputs.tags_aws_lambda }},${{ needs.release_arm64.outputs.tags_aws_lambda }}"
alternate_registry: thecodingmachine
- name: Clean
uses: ./.github/actions/clean
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.release_amd64.outputs.tags }},${{ needs.release_386.outputs.tags }},${{ needs.release_arm64.outputs.tags }},${{ needs.release_arm_v7.outputs.tags }}"
tags: "${{ needs.release_amd64.outputs.tags }},${{ needs.release_386.outputs.tags }},${{ needs.release_arm64.outputs.tags }},${{ needs.release_arm_v7.outputs.tags }},${{ needs.release_amd64.outputs.tags_aws_lambda }},${{ needs.release_arm64.outputs.tags_aws_lambda }}"

View File

@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Go
uses: actions/setup-go@v5
@@ -29,16 +29,16 @@ jobs:
go-version-file: go.mod
- name: Run linters
uses: golangci/golangci-lint-action@v7
uses: golangci/golangci-lint-action@v8
with:
version: v2.0.2
version: v2.4.0
lint-prettier:
name: Lint non-Golang codebase
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
@@ -59,7 +59,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Go
uses: actions/setup-go@v5
@@ -78,9 +78,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Build, test and push
id: build_test_push
@@ -101,9 +102,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Build, test and push
id: build_test_push
@@ -124,9 +126,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Build, test and push
id: build_test_push
@@ -147,9 +150,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Build, test and push
id: build_test_push
@@ -161,17 +165,39 @@ jobs:
platform: linux/arm/v7
alternate_repository: snapshot
merge_clean_snapshot_tags:
merge_clean_snapshot_guard:
needs:
- snapshot_amd64
- snapshot_386
- snapshot_arm64
- snapshot_arm_v7
name: Secrets access check
runs-on: ubuntu-latest
outputs:
continue: ${{ steps.check.outputs.continue }}
steps:
- name: Check
id: check
run: |
if [ -n "${{ secrets.DOCKERHUB_USERNAME }}" ]; then
echo "continue=true" >> "$GITHUB_OUTPUT"
else
echo "continue=false" >> "$GITHUB_OUTPUT"
fi
merge_clean_snapshot_tags:
if: needs.merge_clean_snapshot_guard.outputs.continue == 'true'
needs:
- merge_clean_snapshot_guard
- snapshot_amd64
- snapshot_386
- snapshot_arm64
- snapshot_arm_v7
name: Merge and clean snapshot tags
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Merge
uses: ./.github/actions/merge
@@ -180,12 +206,19 @@ jobs:
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.snapshot_amd64.outputs.tags }},${{ needs.snapshot_386.outputs.tags }},${{ needs.snapshot_arm64.outputs.tags }},${{ needs.snapshot_arm_v7.outputs.tags }}"
- name: Merge AWS Lambda
uses: ./.github/actions/merge
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.snapshot_amd64.outputs.tags_aws_lambda }},${{ needs.snapshot_arm64.outputs.tags_aws_lambda }}"
- name: Clean
uses: ./.github/actions/clean
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.snapshot_amd64.outputs.tags }},${{ needs.snapshot_386.outputs.tags }},${{ needs.snapshot_arm64.outputs.tags }},${{ needs.snapshot_arm_v7.outputs.tags }}"
tags: "${{ needs.snapshot_amd64.outputs.tags }},${{ needs.snapshot_386.outputs.tags }},${{ needs.snapshot_arm64.outputs.tags }},${{ needs.snapshot_arm_v7.outputs.tags }},${{ needs.snapshot_amd64.outputs.tags_aws_lambda }},${{ needs.snapshot_arm64.outputs.tags_aws_lambda }}"
edge_amd64:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
@@ -196,9 +229,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Build, test and push
id: build_test_push
@@ -218,9 +252,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Build, test and push
id: build_test_push
@@ -240,9 +275,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Build, test and push
id: build_test_push
@@ -262,9 +298,10 @@ jobs:
outputs:
tags: ${{ steps.build_test_push.outputs.tags }}
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Build, test and push
id: build_test_push
@@ -285,7 +322,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Merge
uses: ./.github/actions/merge
@@ -295,9 +332,17 @@ jobs:
tags: "${{ needs.edge_amd64.outputs.tags }},${{ needs.edge_386.outputs.tags }},${{ needs.edge_arm64.outputs.tags }},${{ needs.edge_arm_v7.outputs.tags }}"
alternate_registry: thecodingmachine
- name: Merge AWS Lambda
uses: ./.github/actions/merge
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.edge_amd64.outputs.tags_aws_lambda }},${{ needs.edge_arm64.outputs.tags_aws_lambda }}"
alternate_registry: thecodingmachine
- name: Clean
uses: ./.github/actions/clean
with:
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
tags: "${{ needs.edge_amd64.outputs.tags }},${{ needs.edge_386.outputs.tags }},${{ needs.edge_arm64.outputs.tags }},${{ needs.edge_arm_v7.outputs.tags }}"
tags: "${{ needs.edge_amd64.outputs.tags }},${{ needs.edge_386.outputs.tags }},${{ needs.edge_arm64.outputs.tags }},${{ needs.edge_arm_v7.outputs.tags }},${{ needs.edge_amd64.outputs.tags_aws_lambda }},${{ needs.edge_arm64.outputs.tags_aws_lambda }}"

View File

@@ -11,9 +11,10 @@ jobs:
cleanup:
name: Cleanup Docker images
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Cleanup
uses: ./.github/actions/clean

2
.gitignore vendored
View File

@@ -1,5 +1,3 @@
/coverage.html
/coverage.txt
.idea
.vscode
.DS_Store

View File

@@ -7,17 +7,12 @@ help: ## Show the help
.PHONY: build
build: ## Build the Gotenberg's Docker image
docker build \
--build-arg GOLANG_VERSION=$(GOLANG_VERSION) \
--build-arg GOTENBERG_VERSION=$(GOTENBERG_VERSION) \
--build-arg GOTENBERG_USER_GID=$(GOTENBERG_USER_GID) \
--build-arg GOTENBERG_USER_UID=$(GOTENBERG_USER_UID) \
--build-arg NOTO_COLOR_EMOJI_VERSION=$(NOTO_COLOR_EMOJI_VERSION) \
--build-arg PDFTK_VERSION=$(PDFTK_VERSION) \
--build-arg PDFCPU_VERSION=$(PDFCPU_VERSION) \
-t $(DOCKER_REGISTRY)/$(DOCKER_REPOSITORY):$(GOTENBERG_VERSION) \
-f $(DOCKERFILE) $(DOCKER_BUILD_CONTEXT)
GOTENBERG_HIDE_BANNER=false
GOTENBERG_GRACEFUL_SHUTDOWN_DURATION=30s
GOTENBERG_BUILD_DEBUG_DATA=true
API_PORT=3000
API_PORT_FROM_ENV=
API_BIND_IP=
@@ -72,6 +67,7 @@ PROMETHEUS_NAMESPACE=gotenberg
PROMETHEUS_COLLECT_INTERVAL=1s
PROMETHEUS_DISABLE_ROUTE_LOGGING=false
PROMETHEUS_DISABLE_COLLECT=false
WEBHOOK_ENABLE_SYNC_MODE=false
WEBHOOK_ALLOW_LIST=
WEBHOOK_DENY_LIST=
WEBHOOK_ERROR_ALLOW_LIST=
@@ -90,7 +86,9 @@ run: ## Start a Gotenberg container
-e GOTENBERG_API_BASIC_AUTH_PASSWORD=$(GOTENBERG_API_BASIC_AUTH_PASSWORD) \
$(DOCKER_REGISTRY)/$(DOCKER_REPOSITORY):$(GOTENBERG_VERSION) \
gotenberg \
--gotenberg-hide-banner=$(GOTENBERG_HIDE_BANNER) \
--gotenberg-graceful-shutdown-duration=$(GOTENBERG_GRACEFUL_SHUTDOWN_DURATION) \
--gotenberg-build-debug-data="$(GOTENBERG_BUILD_DEBUG_DATA)" \
--api-port=$(API_PORT) \
--api-port-from-env=$(API_PORT_FROM_ENV) \
--api-bind-ip=$(API_BIND_IP) \
@@ -143,6 +141,7 @@ run: ## Start a Gotenberg container
--prometheus-collect-interval=$(PROMETHEUS_COLLECT_INTERVAL) \
--prometheus-disable-route-logging=$(PROMETHEUS_DISABLE_ROUTE_LOGGING) \
--prometheus-disable-collect=$(PROMETHEUS_DISABLE_COLLECT) \
--webhook-enable-sync-mode="$(WEBHOOK_ENABLE_SYNC_MODE)" \
--webhook-allow-list="$(WEBHOOK_ALLOW_LIST)" \
--webhook-deny-list="$(WEBHOOK_DENY_LIST)" \
--webhook-error-allow-list=$(WEBHOOK_ERROR_ALLOW_LIST) \

View File

@@ -43,12 +43,9 @@ Head to the [documentation](https://gotenberg.dev/docs/getting-started/introduct
<a href="https://thecodingmachine.com">
<img src="https://user-images.githubusercontent.com/8983173/130324668-9d6e7b35-53a3-49c7-a574-38190d2bd6b0.png" alt="TheCodingMachine Logo" width="333" height="163" />
</a>
<a href="https://zolsec.com?utm_source=gotenberg_github&utm_medium=website" target="_blank">
<img src="https://github.com/gotenberg/gotenberg/assets/8983173/707ccc97-a79b-4dcb-8fc8-6827366e5be3" alt="Zolsec Logo" width="333" height="163" />
</a>
<a href="https://pdfme.com?utm_source=gotenberg_github&utm_medium=website" target="_blank">
<img src="https://github.com/user-attachments/assets/2a75dd40-ca18-4d34-acd5-5dd474595168" alt="pdfme Logo" width="333" height="163" />
</a>
</p>
Sponsorships help maintaining and improving Gotenberg - [become a sponsor](https://github.com/sponsors/gulien) ❤️
Sponsorships help maintain and improve Gotenberg - [become a sponsor](https://github.com/sponsors/gulien) ❤️

View File

@@ -2,7 +2,7 @@
## Supported Versions
Please ensure to keep your environment up-to-date and use only the latest version of Gotenberg.
Please ensure to keep your environment up to date and use only the latest version of Gotenberg.
Security updates and patches will be applied only to the most recent version.
## Reporting a Vulnerability

View File

@@ -1,17 +1,17 @@
# ARG instructions do not create additional layers. Instead, next layers will
# concatenate them. Also, we have to repeat ARG instructions in each build
# stage that uses them.
ARG GOLANG_VERSION
ARG GOLANG_VERSION=1.25.0
# ----------------------------------------------
# pdfcpu binary build stage
# ----------------------------------------------
# Note: this stage is required as pdfcpu does not release an armhf variant by
# default.
FROM golang:$GOLANG_VERSION AS pdfcpu-binary-stage
ARG PDFCPU_VERSION
# See https://github.com/pdfcpu/pdfcpu/releases.
ARG PDFCPU_VERSION=v0.11.0
ENV CGO_ENABLED=0
# Define the working directory outside of $GOPATH (we're using go modules).
@@ -33,7 +33,7 @@ RUN go build -o pdfcpu -ldflags "-s -w -X 'main.version=$PDFCPU_VERSION' -X 'git
# ----------------------------------------------
FROM golang:$GOLANG_VERSION AS gotenberg-binary-stage
ARG GOTENBERG_VERSION
ARG GOTENBERG_VERSION=snapshot
ENV CGO_ENABLED=0
# Define the working directory outside of $GOPATH (we're using go modules).
@@ -49,25 +49,77 @@ RUN go mod download &&\
COPY cmd ./cmd
COPY pkg ./pkg
RUN go build -o gotenberg -ldflags "-X 'github.com/gotenberg/gotenberg/v8/cmd.Version=$GOTENBERG_VERSION'" cmd/gotenberg/main.go
RUN go build -o gotenberg -ldflags "-s -w -X 'github.com/gotenberg/gotenberg/v8/cmd.Version=$GOTENBERG_VERSION'" cmd/gotenberg/main.go
# ----------------------------------------------
# Compress Golang binaries stage
# ----------------------------------------------
FROM debian:13-slim AS compress-go-binaries-stage
RUN \
echo "deb http://deb.debian.org/debian bookworm-backports main" >> /etc/apt/sources.list &&\
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends -t bookworm-backports upx-ucl
COPY --from=pdfcpu-binary-stage /home/pdfcpu /home/pdfcpu
COPY --from=gotenberg-binary-stage /home/gotenberg /home/gotenberg
RUN \
upx-ucl --best /home/pdfcpu &&\
upx-ucl --best /home/gotenberg
# ----------------------------------------------
# Custom JRE stage
# Credits: https://github.com/jodconverter/docker-image-jodconverter-runtime
# ----------------------------------------------
FROM debian:13-slim AS custom-jre-stage
RUN \
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends default-jdk-headless binutils
# Note: jdeps helps finding which modules a JAR requires.
# Currently only for PDFtk, as we don't rely on LibreOffice UNO Java SDK.
ENV JAVA_MODULES=java.base,java.desktop,java.naming,java.sql
RUN jlink \
--add-modules $JAVA_MODULES \
--strip-debug \
--no-man-pages \
--no-header-files \
--compress=2 \
--output /custom-jre
# ----------------------------------------------
# Base image stage
# ----------------------------------------------
FROM debian:13-slim AS base-image-stage
COPY --from=custom-jre-stage /custom-jre /opt/java
ENV PATH="/opt/java/bin:${PATH}"
# ----------------------------------------------
# Final stage
# ----------------------------------------------
FROM debian:12-slim
FROM base-image-stage
ARG GOTENBERG_VERSION
ARG GOTENBERG_USER_GID
ARG GOTENBERG_USER_UID
ARG NOTO_COLOR_EMOJI_VERSION
ARG PDFTK_VERSION
ARG GOTENBERG_VERSION=snapshot
ARG GOTENBERG_USER_GID=1001
ARG GOTENBERG_USER_UID=1001
# See https://github.com/googlefonts/noto-emoji/releases.
ARG NOTO_COLOR_EMOJI_VERSION=v2.048
# See https://gitlab.com/pdftk-java/pdftk/-/releases - Binary package.
ARG PDFTK_VERSION=v3.3.3
LABEL org.opencontainers.image.title="Gotenberg" \
org.opencontainers.image.description="A containerized API for seamless PDF conversion." \
org.opencontainers.image.version="$GOTENBERG_VERSION" \
org.opencontainers.image.authors="Julien Neuhart <neuhart.julien@gmail.com>" \
org.opencontainers.image.documentation="https://gotenberg.dev" \
org.opencontainers.image.source="https://github.com/gotenberg/gotenberg"
org.opencontainers.image.description="A containerized API for seamless PDF conversion." \
org.opencontainers.image.version="$GOTENBERG_VERSION" \
org.opencontainers.image.authors="Julien Neuhart <neuhart.julien@gmail.com>" \
org.opencontainers.image.documentation="https://gotenberg.dev" \
org.opencontainers.image.source="https://github.com/gotenberg/gotenberg"
RUN \
# Create a non-root user.
@@ -82,7 +134,7 @@ RUN \
# Note: tini is a helper for reaping zombie processes.
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends curl gnupg tini python3 default-jre-headless &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends curl gnupg tini python3 python3-distutils-extra &&\
# Cleanup.
# Note: the Debian image does automatically a clean after each install thanks to a hook.
# Therefore, there is no need for apt-get clean.
@@ -123,7 +175,6 @@ RUN \
fonts-crosextra-caladea \
fonts-crosextra-carlito \
fonts-dejavu \
fonts-dejavu-extra \
fonts-liberation \
fonts-liberation2 \
fonts-linuxlibertine \
@@ -143,34 +194,27 @@ RUN \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN \
# Install either Google Chrome stable on amd64 architecture or
# Chromium on other architectures.
# See https://github.com/gotenberg/gotenberg/issues/328.
/bin/bash -c \
'set -e &&\
if [[ "$(dpkg --print-architecture)" == "amd64" ]]; then \
curl https://dl.google.com/linux/linux_signing_key.pub | apt-key add - &&\
echo "deb http://dl.google.com/linux/chrome/deb/ stable main" | tee /etc/apt/sources.list.d/google-chrome.list &&\
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends --allow-unauthenticated google-chrome-stable &&\
mv /usr/bin/google-chrome-stable /usr/bin/chromium; \
else \
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends chromium; \
fi' &&\
# Install Chromium.
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends chromium &&\
# Verify installation.
chromium --version &&\
# Cleanup.
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Set default characterset encoding to UTF-8.
# See:
# https://github.com/gotenberg/gotenberg/issues/104
# https://github.com/gotenberg/gotenberg/issues/730
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
RUN \
# Install LibreOffice & unoconverter.
echo "deb http://deb.debian.org/debian bookworm-backports main" >> /etc/apt/sources.list &&\
apt-get update -qq &&\
apt-get upgrade -yqq &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends -t bookworm-backports libreoffice &&\
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends libreoffice &&\
curl -Ls https://raw.githubusercontent.com/gotenberg/unoconverter/v0.1.1/unoconv -o /usr/bin/unoconverter &&\
chmod +x /usr/bin/unoconverter &&\
# unoconverter will look for the Python binary, which has to be at version 3.
@@ -186,7 +230,7 @@ RUN \
# See https://github.com/gotenberg/gotenberg/pull/273.
curl -o /usr/bin/pdftk-all.jar "https://gitlab.com/api/v4/projects/5024297/packages/generic/pdftk-java/$PDFTK_VERSION/pdftk-all.jar" &&\
chmod a+x /usr/bin/pdftk-all.jar &&\
echo '#!/bin/bash\n\nexec java -jar /usr/bin/pdftk-all.jar "$@"' > /usr/bin/pdftk && \
printf '#!/bin/bash\n\nexec java -jar /usr/bin/pdftk-all.jar "$@"' > /usr/bin/pdftk && \
chmod +x /usr/bin/pdftk &&\
apt-get update -qq &&\
apt-get upgrade -yqq &&\
@@ -200,20 +244,32 @@ RUN \
# Cleanup.
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Support for arbitrary user IDs (OpenShift).
# See:
# https://github.com/gotenberg/gotenberg/issues/1049.
# https://docs.redhat.com/en/documentation/openshift_container_platform/4.15/html/images/creating-images#use-uid_create-images.
RUN \
usermod -aG root gotenberg &&\
chgrp -R 0 /home/gotenberg &&\
chmod -R g=u /home/gotenberg
# Improve fonts subpixel hinting and smoothing.
# Credits:
# https://github.com/arachnys/athenapdf/issues/69.
# https://github.com/arachnys/athenapdf/commit/ba25a8d80a25d08d58865519c4cd8756dc9a336d.
COPY build/fonts.conf /etc/fonts/conf.d/100-gotenberg.conf
# Copy the pdfcpu binary from the pdfcpu-binary-stage.
COPY --from=pdfcpu-binary-stage /home/pdfcpu /usr/bin/
# Copy dictionnaries so that hypens work on Chromium.
# See https://github.com/gotenberg/gotenberg/issues/1293.
COPY --chown=gotenberg:gotenberg build/chromium-hyphen-data /home/gotenberg/chromium-hyphen-data
# Copy the Gotenberg binary from the gotenberg-binary-stage.
COPY --from=gotenberg-binary-stage /home/gotenberg /usr/bin/
# Copy the Golang binaries.
COPY --from=compress-go-binaries-stage /home/pdfcpu /usr/bin/
COPY --from=compress-go-binaries-stage /home/gotenberg /usr/bin/
# Environment variables required by modules or else.
ENV CHROMIUM_BIN_PATH=/usr/bin/chromium
ENV CHROMIUM_HYPHEN_DATA_DIR_PATH=/home/gotenberg/chromium-hyphen-data
ENV LIBREOFFICE_BIN_PATH=/usr/lib/libreoffice/program/soffice.bin
ENV UNOCONVERTER_BIN_PATH=/usr/bin/unoconverter
ENV PDFTK_BIN_PATH=/usr/bin/pdftk

View File

@@ -0,0 +1,23 @@
ARG DOCKER_REGISTRY
ARG DOCKER_REPOSITORY
ARG GOTENBERG_VERSION
FROM $DOCKER_REGISTRY/$DOCKER_REPOSITORY:$GOTENBERG_VERSION
USER root
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.9.1 /lambda-adapter /opt/extensions/lambda-adapter
# AWS.
ENV AWS_LWA_PORT=3000
ENV AWS_LWA_READINESS_CHECK_PATH=/health
ENV AWS_LWA_INVOKE_MODE=response_stream
# Gotenberg.
ENV API_PORT_FROM_ENV=AWS_LWA_PORT
ENV CHROMIUM_AUTO_START=true
ENV LIBREOFFICE_AUTO_START=true
ENV WEBHOOK_ENABLE_SYNC_MODE=true
ENV GOTENBERG_BUILD_DEBUG_DATA=false
USER gotenberg

View File

@@ -11,4 +11,12 @@ USER root
# See https://github.com/gotenberg/gotenberg/issues/90#issuecomment-543551353.
RUN chown gotenberg: /usr/bin/tini
# Gotenberg.
ENV API_PORT_FROM_ENV=PORT
ENV CHROMIUM_AUTO_START=true
ENV LIBREOFFICE_AUTO_START=true
ENV WEBHOOK_ENABLE_SYNC_MODE=true
ENV GOTENBERG_BUILD_DEBUG_DATA=false
ENV LOG_ENABLE_GCP_FIELDS=true
USER gotenberg

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,5 @@
{
"manifest_version": 2,
"name": "hyphens-data",
"version": "120.0.6050.0"
}

View File

@@ -2,6 +2,7 @@ package gotenbergcmd
import (
"context"
"errors"
"fmt"
"os"
"os/signal"
@@ -35,12 +36,13 @@ var Version = "snapshot"
// Run starts the Gotenberg application. Call this in the main of your program.
func Run() {
fmt.Printf(banner, Version)
gotenberg.Version = Version
// Create the root FlagSet and adds the modules flags to it.
fs := flag.NewFlagSet("gotenberg", flag.ExitOnError)
fs.Bool("gotenberg-hide-banner", false, "Hide the banner")
fs.Duration("gotenberg-graceful-shutdown-duration", time.Duration(30)*time.Second, "Set the graceful shutdown duration")
fs.Bool("gotenberg-build-debug-data", true, "Set if build data is needed")
descriptors := gotenberg.GetModuleDescriptors()
var modsInfo string
@@ -49,8 +51,6 @@ func Run() {
modsInfo += desc.ID + " "
}
fmt.Printf("[SYSTEM] modules: %s\n", modsInfo)
// Parse the flags.
err := fs.Parse(os.Args[1:])
if err != nil {
@@ -88,10 +88,14 @@ func Run() {
// Create a wrapper around our flags.
parsedFlags := gotenberg.ParsedFlags{FlagSet: fs}
// Get the graceful shutdown duration.
hideBanner := parsedFlags.MustBool("gotenberg-hide-banner")
gracefulShutdownDuration := parsedFlags.MustDuration("gotenberg-graceful-shutdown-duration")
if !hideBanner {
fmt.Printf(banner, Version)
}
fmt.Printf("[SYSTEM] modules: %s\n", modsInfo)
ctx := gotenberg.NewContext(parsedFlags, descriptors)
// Start application modules.
@@ -137,8 +141,10 @@ func Run() {
}(l.(gotenberg.SystemLogger))
}
// Build the debug data.
gotenberg.BuildDebug(ctx)
if parsedFlags.MustBool("gotenberg-build-debug-data") {
// Build the debug data.
gotenberg.BuildDebug(ctx)
}
quit := make(chan os.Signal, 1)
@@ -170,7 +176,9 @@ func Run() {
id := app.(gotenberg.Module).Descriptor().ID
err = app.Stop(gracefulShutdownCtx)
if err != nil {
if errors.Is(err, gotenberg.ErrCancelGracefulShutdownContext) {
cancel()
} else if err != nil {
return fmt.Errorf("stopping %s: %w", id, err)
}

110
go.mod
View File

@@ -1,60 +1,51 @@
module github.com/gotenberg/gotenberg/v8
go 1.24.0
go 1.25.0
require (
github.com/alexliesenfeld/health v0.8.0
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/alexliesenfeld/health v0.8.1
github.com/barasher/go-exiftool v1.10.0
github.com/chromedp/cdproto v0.0.0-20250319231242-a755498943c8
github.com/chromedp/chromedp v0.13.3
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d
github.com/chromedp/chromedp v0.14.1
github.com/cucumber/godog v0.15.1
github.com/dlclark/regexp2 v1.11.5
github.com/docker/docker v28.3.3+incompatible
github.com/docker/go-connections v0.6.0
github.com/google/uuid v1.6.0
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/labstack/echo/v4 v4.13.3
github.com/hashicorp/go-retryablehttp v0.7.8
github.com/labstack/echo/v4 v4.13.4
github.com/labstack/gommon v0.4.2
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mholt/archives v0.1.3
github.com/microcosm-cc/bluemonday v1.0.27
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/prometheus/client_golang v1.21.1
github.com/prometheus/client_golang v1.23.0
github.com/russross/blackfriday/v2 v2.1.0
github.com/spf13/pflag v1.0.6
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/shirou/gopsutil/v4 v4.25.7
github.com/spf13/pflag v1.0.7
github.com/testcontainers/testcontainers-go v0.38.0
go.uber.org/multierr v1.11.0
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.38.0
golang.org/x/sync v0.12.0
golang.org/x/sys v0.31.0 // indirect
golang.org/x/term v0.30.0
golang.org/x/text v0.23.0
golang.org/x/net v0.43.0
golang.org/x/sync v0.16.0
golang.org/x/term v0.34.0
golang.org/x/text v0.28.0
)
require (
github.com/cucumber/godog v0.15.0
github.com/dlclark/regexp2 v1.11.5
github.com/docker/docker v28.0.4+incompatible
github.com/docker/go-connections v0.5.0
github.com/mholt/archives v0.1.0
github.com/shirou/gopsutil/v4 v4.25.2
github.com/testcontainers/testcontainers-go v0.36.0
)
require (
dario.cat/mergo v1.0.1 // indirect
dario.cat/mergo v1.0.2 // indirect
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/STARRY-S/zip v0.2.2 // indirect
github.com/STARRY-S/zip v0.2.3 // indirect
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bodgit/plumbing v1.3.0 // indirect
github.com/bodgit/sevenzip v1.6.0 // indirect
github.com/bodgit/sevenzip v1.6.1 // indirect
github.com/bodgit/windows v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
github.com/cpuguy83/dockercfg v0.3.2 // indirect
@@ -64,10 +55,10 @@ require (
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
github.com/ebitengine/purego v0.8.2 // indirect
github.com/ebitengine/purego v0.8.4 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-json-experiment/json v0.0.0-20250813233538-9b1f9ea2e11b // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
@@ -76,19 +67,24 @@ require (
github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-memdb v1.3.5 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/magiconair/properties v1.8.10 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mikelolasagasti/xz v1.0.1 // indirect
github.com/minio/minlz v1.0.1 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/go-archive v0.1.0 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.3.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
@@ -96,32 +92,36 @@ require (
github.com/nwaples/rardecode/v2 v2.1.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.63.0 // indirect
github.com/prometheus/procfs v0.16.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/procfs v0.17.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sorairolake/lzip-go v0.3.7 // indirect
github.com/spf13/afero v1.14.0 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/tklauser/go-sysconf v0.3.15 // indirect
github.com/tklauser/numcpus v0.10.0 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
go.opentelemetry.io/otel v1.37.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/time v0.11.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
google.golang.org/protobuf v1.36.6 // indirect
golang.org/x/crypto v0.41.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/time v0.12.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250728155136-f173205681a0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 // indirect
google.golang.org/protobuf v1.36.7 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

209
go.sum
View File

@@ -14,23 +14,23 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/STARRY-S/zip v0.2.2 h1:8QeCbIi1Z9U5MgoDARJR1ClbBo9RD46SmVy+dl0woCk=
github.com/STARRY-S/zip v0.2.2/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk=
github.com/alexliesenfeld/health v0.8.0 h1:lCV0i+ZJPTbqP7LfKG7p3qZBl5VhelwUFCIVWl77fgk=
github.com/alexliesenfeld/health v0.8.0/go.mod h1:TfNP0f+9WQVWMQRzvMUjlws4ceXKEL3WR+6Hp95HUFc=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4=
github.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk=
github.com/alexliesenfeld/health v0.8.1 h1:wdE3vt+cbJotiR8DGDBZPKHDFoJbAoWEfQTcqrmedUg=
github.com/alexliesenfeld/health v0.8.1/go.mod h1:TfNP0f+9WQVWMQRzvMUjlws4ceXKEL3WR+6Hp95HUFc=
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/barasher/go-exiftool v1.10.0 h1:f5JY5jc42M7tzR6tbL9508S2IXdIcG9QyieEXNMpIhs=
@@ -39,8 +39,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=
github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=
github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A=
github.com/bodgit/sevenzip v1.6.0/go.mod h1:zOBh9nJUof7tcrlqJFv1koWRrhz3LbDbUNngkuZxLMc=
github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4=
github.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8=
github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=
github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
@@ -48,16 +48,20 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chromedp/cdproto v0.0.0-20250319231242-a755498943c8 h1:AqW2bDQf67Zbq6Tpop/+yJSIknxhiQecO2B8jNYTAPs=
github.com/chromedp/cdproto v0.0.0-20250319231242-a755498943c8/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
github.com/chromedp/chromedp v0.13.3 h1:c6nTn97XQBykzcXiGYL5LLebw3h3CEyrCihm4HquYh0=
github.com/chromedp/chromedp v0.13.3/go.mod h1:khsDP9OP20GrowpJfZ7N05iGCwcAYxk7qf9AZBzR3Qw=
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d h1:ZtA1sedVbEW7EW80Iz2GR3Ye6PwbJAJXjv7D74xG6HU=
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
github.com/chromedp/chromedp v0.14.1 h1:0uAbnxewy/Q+Bg7oafVePE/6EXEho9hnaC38f+TTENg=
github.com/chromedp/chromedp v0.14.1/go.mod h1:rHzAv60xDE7VNy/MYtTUrYreSc0ujt2O1/C3bzctYBo=
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
@@ -69,8 +73,8 @@ github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI=
github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0=
github.com/cucumber/godog v0.15.0 h1:51AL8lBXF3f0cyA5CV4TnJFCTHpgiy+1x1Hb3TtZUmo=
github.com/cucumber/godog v0.15.0/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces=
github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI=
github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8=
github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI=
github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s=
github.com/cucumber/messages/go/v22 v22.0.0/go.mod h1:aZipXTKc0JnjCsXrJnuZpWhtay93k7Rn3Dee7iyPJjs=
@@ -81,17 +85,17 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/docker/docker v28.0.4+incompatible h1:JNNkBctYKurkw6FrHfKqY0nKIDf5nrbxjVBtS+cdcok=
github.com/docker/docker v28.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
@@ -100,11 +104,11 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6M9UQCavhwmO6ZsrYLfG8zVFWfEfMS2MXPkSY=
github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
github.com/go-json-experiment/json v0.0.0-20250813233538-9b1f9ea2e11b h1:6Q4zRHXS/YLOl9Ng1b1OOOBWMidAQZR3Gel0UKPC/KU=
github.com/go-json-experiment/json v0.0.0-20250813233538-9b1f9ea2e11b/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
@@ -154,11 +158,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
@@ -169,10 +170,8 @@ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh
github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg=
github.com/hashicorp/go-memdb v1.3.5 h1:b3taDMxCBCBVgyRrS1AZVHO14ubMYZB++QpNhBg+Nyo=
github.com/hashicorp/go-memdb v1.3.5/go.mod h1:8IVKKBkVe+fxFgdFOYxzQQNjz+sWCyHCdIC/+5+Vy1Y=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=
github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
@@ -205,32 +204,40 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA=
github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mholt/archives v0.1.0 h1:FacgJyrjiuyomTuNA92X5GyRBRZjE43Y/lrzKIlF35Q=
github.com/mholt/archives v0.1.0/go.mod h1:j/Ire/jm42GN7h90F5kzj6hf6ZFzEH66de+hmjEKu+I=
github.com/mholt/archives v0.1.3 h1:aEAaOtNra78G+TvV5ohmXrJOAzf++dIlYeDW3N9q458=
github.com/mholt/archives v0.1.3/go.mod h1:LUCGp++/IbV/I0Xq4SzcIR6uwgeh2yjnQWamjRQfLTU=
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0=
github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc=
github.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A=
github.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
@@ -255,31 +262,33 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/shirou/gopsutil/v4 v4.25.2 h1:NMscG3l2CqtWFS86kj3vP7soOczqrQYIEhO/pMvvQkk=
github.com/shirou/gopsutil/v4 v4.25.2/go.mod h1:34gBYJzyqCDT11b6bMHP0XCvWeU3J61XRT7a2EmCRTA=
github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM=
github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sorairolake/lzip-go v0.3.7 h1:vP2uiD/NoklLyzYMdgOWkZME0ulkSfVTTE4MNRKCwNs=
github.com/sorairolake/lzip-go v0.3.7/go.mod h1:THOHr0FlNVCw2eOIEE9shFJAG1QxQg/pf2XUPAmNIqg=
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -294,10 +303,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/testcontainers/testcontainers-go v0.36.0 h1:YpffyLuHtdp5EUsI5mT4sRw8GZhO/5ozyDT1xWGXt00=
github.com/testcontainers/testcontainers-go v0.36.0/go.mod h1:yk73GVJ0KUZIHUtFna6MO7QS144qYpoY8lEEtU9Hed0=
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
github.com/testcontainers/testcontainers-go v0.38.0 h1:d7uEapLcv2P8AvH8ahLqDMMxda2W9gQN1nRbHS28HBw=
github.com/testcontainers/testcontainers-go v0.38.0/go.mod h1:C52c9MoHpWO+C4aqmgSU+hxlR5jlEayWtgYrb8Pzz1w=
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
@@ -322,24 +329,24 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -354,8 +361,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -401,8 +408,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -416,8 +423,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -442,13 +449,13 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -456,12 +463,12 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -519,10 +526,10 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f h1:2yNACc1O40tTnrsbk9Cv6oxiW8pxI/pXj0wRtdlYmgY=
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/api v0.0.0-20250728155136-f173205681a0 h1:0UOBWO4dC+e51ui0NFKSPbkHHiQ4TmrEfEZMLDyRmY8=
google.golang.org/genproto/googleapis/api v0.0.0-20250728155136-f173205681a0/go.mod h1:8ytArBbtOy2xfht+y2fqKd5DRDJRUQhqbyEnQ4bDChs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 h1:MAKi5q709QWfnkkpNQ0M12hYJ1+e8qYVDyowc4U1XZM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -530,10 +537,10 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@@ -543,8 +550,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

57
package-lock.json generated
View File

@@ -5,9 +5,9 @@
"packages": {
"": {
"devDependencies": {
"prettier": "3.5.2",
"prettier-plugin-gherkin": "^3.1.1",
"prettier-plugin-sh": "^0.15.0"
"prettier": "3.6.2",
"prettier-plugin-gherkin": "^3.1.2",
"prettier-plugin-sh": "^0.18.0"
}
},
"node_modules/@cucumber/gherkin": {
@@ -63,6 +63,16 @@
"uuid": "9.0.1"
}
},
"node_modules/@reteps/dockerfmt": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/@reteps/dockerfmt/-/dockerfmt-0.3.6.tgz",
"integrity": "sha512-Tb5wIMvBf/nLejTQ61krK644/CEMB/cpiaIFXqGApfGqO3GwcR3qnI0DbmkFVCl2OyEp8LnLX3EkucoL0+tbFg==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^v12.20.0 || ^14.13.0 || >=16.0.0"
}
},
"node_modules/@types/uuid": {
"version": "9.0.6",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.6.tgz",
@@ -77,17 +87,10 @@
"dev": true,
"license": "MIT"
},
"node_modules/mvdan-sh": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/mvdan-sh/-/mvdan-sh-0.10.1.tgz",
"integrity": "sha512-kMbrH0EObaKmK3nVRKUIIya1dpASHIEusM13S4V1ViHFuxuNxCo+arxoa6j/dbV22YBGjl7UKJm9QQKJ2Crzhg==",
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/prettier": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.2.tgz",
"integrity": "sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==",
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"dev": true,
"license": "MIT",
"bin": {
@@ -101,9 +104,9 @@
}
},
"node_modules/prettier-plugin-gherkin": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/prettier-plugin-gherkin/-/prettier-plugin-gherkin-3.1.1.tgz",
"integrity": "sha512-cCfjqKMdR2a8jOf8yKg32iUfRq0Dfmx+K2qTMOD/ixJJq0Rp7QS8BaoABWC7CDGXbvOkVeWOvzhxWvYcEbjglw==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/prettier-plugin-gherkin/-/prettier-plugin-gherkin-3.1.2.tgz",
"integrity": "sha512-LgehRNKCAqZsoE/yblmqXYfMpEK2mhVWQKNj/TFzeLR+0rhFGHqq3RlYcYhPgzbr0n6w2Bv+0Gm1yxNdzkdacw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -113,14 +116,14 @@
}
},
"node_modules/prettier-plugin-sh": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/prettier-plugin-sh/-/prettier-plugin-sh-0.15.0.tgz",
"integrity": "sha512-U0PikJr/yr2bzzARl43qI0mApBj0C1xdAfA04AZa6LnvIKawXHhuy2fFo6LNA7weRzGlAiNbaEFfKMFo0nZr/A==",
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/prettier-plugin-sh/-/prettier-plugin-sh-0.18.0.tgz",
"integrity": "sha512-cW1XL27FOJQ/qGHOW6IHwdCiNWQsAgK+feA8V6+xUTaH0cD3Mh+tFAtBvEEWvuY6hTDzRV943Fzeii+qMOh7nQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"mvdan-sh": "^0.10.1",
"sh-syntax": "^0.4.2"
"@reteps/dockerfmt": "^0.3.6",
"sh-syntax": "^0.5.8"
},
"engines": {
"node": ">=16.0.0"
@@ -129,7 +132,7 @@
"url": "https://opencollective.com/unts"
},
"peerDependencies": {
"prettier": "^3.0.3"
"prettier": "^3.6.0"
}
},
"node_modules/reflect-metadata": {
@@ -140,19 +143,19 @@
"license": "Apache-2.0"
},
"node_modules/sh-syntax": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/sh-syntax/-/sh-syntax-0.4.2.tgz",
"integrity": "sha512-/l2UZ5fhGZLVZa16XQM9/Vq/hezGGbdHeVEA01uWjOL1+7Ek/gt6FquW0iKKws4a9AYPYvlz6RyVvjh3JxOteg==",
"version": "0.5.8",
"resolved": "https://registry.npmjs.org/sh-syntax/-/sh-syntax-0.5.8.tgz",
"integrity": "sha512-JfVoxf4FxQI5qpsPbkHhZo+n6N9YMJobyl4oGEUBb/31oQYlgTjkXQD8PBiafS2UbWoxrTO0Z5PJUBXEPAG1Zw==",
"dev": true,
"license": "MIT",
"dependencies": {
"tslib": "^2.6.2"
"tslib": "^2.8.1"
},
"engines": {
"node": ">=16.0.0"
},
"funding": {
"url": "https://opencollective.com/unts"
"url": "https://opencollective.com/sh-syntax"
}
},
"node_modules/tslib": {

View File

@@ -1,7 +1,7 @@
{
"devDependencies": {
"prettier": "3.5.2",
"prettier-plugin-gherkin": "^3.1.1",
"prettier-plugin-sh": "^0.15.0"
"prettier": "3.6.2",
"prettier-plugin-gherkin": "^3.1.2",
"prettier-plugin-sh": "^0.18.0"
}
}

View File

@@ -74,7 +74,7 @@ func (cmd *Cmd) Start() error {
}
// Wait waits for the command to complete. It should be called when using the
// Start method, so that the command does not leak zombies.
// Start method so that the command does not leak zombies.
func (cmd *Cmd) Wait() error {
err := cmd.process.Wait()
if err != nil {
@@ -84,7 +84,7 @@ func (cmd *Cmd) Wait() error {
return nil
}
// Exec executes the command and wait for its completion or until the context
// Exec executes the command and waits for its completion or until the context
// is done. In any case, it kills the unix process and all its children.
func (cmd *Cmd) Exec() (int, error) {
if cmd.ctx == nil {

View File

@@ -5,7 +5,7 @@ import (
"reflect"
)
// Context is a struct which helps to initialize modules. When provisioning, a
// Context is a struct that helps to initialize modules. When provisioning, a
// module may use the context to get other modules that it needs internally.
type Context struct {
flags ParsedFlags
@@ -58,7 +58,7 @@ func (ctx *Context) Module(kind interface{}) (interface{}, error) {
return mods[0], nil
}
// Modules returns the list of modules which satisfies the requested interface.
// Modules return the list of modules which satisfies the requested interface.
//
// func (m *YourModule) Provision(ctx *gotenberg.Context) error {
// mods, _ := ctx.Modules(new(ModuleInterface))

View File

@@ -23,7 +23,7 @@ func (o *OsMkdirAll) MkdirAll(path string, perm os.FileMode) error { return os.M
// PathRename defines the method signature for renaming files. Implement this
// interface if you don't want to rely on [os.Rename], notably for testing
// purpose.
// purposes.
type PathRename interface {
// Rename uses the same signature as [os.Rename].
Rename(oldpath, newpath string) error

View File

@@ -11,7 +11,7 @@ import (
)
// GarbageCollect scans the root path and deletes files or directories with
// names containing specific substrings and before a given experiation time.
// names containing specific substrings and before a given expiration time.
func GarbageCollect(logger *zap.Logger, rootPath string, includeSubstr []string, expirationTime time.Time) error {
logger = logger.Named("gc")

View File

@@ -28,29 +28,29 @@ func TestGarbageCollect(t *testing.T) {
{
scenario: "remove include substrings",
rootPath: func() string {
path := fmt.Sprintf("%s/a_directory", os.TempDir())
p := fmt.Sprintf("%s/a_directory", os.TempDir())
err := os.MkdirAll(path, 0o755)
err := os.MkdirAll(p, 0o755)
if err != nil {
t.Fatalf("expected no error but got: %v", err)
}
err = os.WriteFile(fmt.Sprintf("%s/a_foo_file", path), []byte{1}, 0o755)
err = os.WriteFile(fmt.Sprintf("%s/a_foo_file", p), []byte{1}, 0o755)
if err != nil {
t.Fatalf("expected no error but got: %v", err)
}
err = os.WriteFile(fmt.Sprintf("%s/a_bar_file", path), []byte{1}, 0o755)
err = os.WriteFile(fmt.Sprintf("%s/a_bar_file", p), []byte{1}, 0o755)
if err != nil {
t.Fatalf("expected no error but got: %v", err)
}
err = os.WriteFile(fmt.Sprintf("%s/a_baz_file", path), []byte{1}, 0o755)
err = os.WriteFile(fmt.Sprintf("%s/a_baz_file", p), []byte{1}, 0o755)
if err != nil {
t.Fatalf("expected no error but got: %v", err)
}
return path
return p
}(),
includeSubstr: []string{"foo", path.Join(os.TempDir(), "/a_directory/a_bar_file")},
expectError: false,
@@ -81,18 +81,18 @@ func TestGarbageCollect(t *testing.T) {
}
for _, name := range tc.expectNotExists {
path := fmt.Sprintf("%s/%s", tc.rootPath, name)
_, err = os.Stat(path)
p := fmt.Sprintf("%s/%s", tc.rootPath, name)
_, err = os.Stat(p)
if !os.IsNotExist(err) {
t.Errorf("expected '%s' not to exist but it does: %v", path, err)
t.Errorf("expected '%s' not to exist but it does: %v", p, err)
}
}
for _, name := range tc.expectExists {
path := fmt.Sprintf("%s/%s", tc.rootPath, name)
_, err = os.Stat(path)
p := fmt.Sprintf("%s/%s", tc.rootPath, name)
_, err = os.Stat(p)
if os.IsNotExist(err) {
t.Errorf("expected '%s' to exist but it does not: %v", path, err)
t.Errorf("expected '%s' to exist but it does not: %v", p, err)
}
}
})

View File

@@ -18,7 +18,7 @@ type LoggerProvider interface {
Logger(mod Module) (*zap.Logger, error)
}
// LeveledLogger is wrapper around a [zap.Logger] so that it may be used by a
// LeveledLogger is a wrapper around a [zap.Logger] so that it may be used by a
// [retryablehttp.Client].
type LeveledLogger struct {
logger *zap.Logger
@@ -31,22 +31,22 @@ func NewLeveledLogger(logger *zap.Logger) *LeveledLogger {
}
}
// Error logs a message at error level using the wrapped zap.Logger.
// Error logs a message at the error level using the wrapped zap.Logger.
func (leveled LeveledLogger) Error(msg string, keysAndValues ...interface{}) {
leveled.logger.Error(fmt.Sprintf("%s: %+v", msg, keysAndValues))
}
// Warn logs a message at warning level using the wrapped zap.Logger.
// Warn logs a message at the warning level using the wrapped zap.Logger.
func (leveled LeveledLogger) Warn(msg string, keysAndValues ...interface{}) {
leveled.logger.Warn(fmt.Sprintf("%s: %+v", msg, keysAndValues))
}
// Info logs a message at info level using the wrapped zap.Logger.
// Info logs a message at the info level using the wrapped zap.Logger.
func (leveled LeveledLogger) Info(msg string, keysAndValues ...interface{}) {
leveled.logger.Info(fmt.Sprintf("%s: %+v", msg, keysAndValues))
}
// Debug logs a message at debug level using the wrapped zap.Logger.
// Debug logs a message at the debug level using the wrapped zap.Logger.
func (leveled LeveledLogger) Debug(msg string, keysAndValues ...interface{}) {
leveled.logger.Debug(fmt.Sprintf("%s: %+v", msg, keysAndValues))
}

View File

@@ -13,7 +13,7 @@ var (
ErrPdfEngineMethodNotSupported = errors.New("method not supported")
// ErrPdfSplitModeNotSupported is returned when the Split method of the
// PdfEngine interface does not sumport a requested PDF split mode.
// PdfEngine interface does not support a requested PDF split mode.
ErrPdfSplitModeNotSupported = errors.New("split mode not supported")
// ErrPdfFormatNotSupported is returned when the Convert method of the
@@ -86,7 +86,7 @@ type PdfFormats struct {
}
// PdfEngine provides an interface for operations on PDFs. Implementations
// can utilize various tools like PDFtk, or implement functionality directly in
// can use various tools like PDFtk, or implement functionality directly in
// Go.
//
//nolint:dupl

View File

@@ -0,0 +1,8 @@
package gotenberg
import "errors"
// ErrCancelGracefulShutdownContext tells that a module wants to abort a
// graceful shutdown and stops Gotenberg right away as there are no more
// ongoing processes.
var ErrCancelGracefulShutdownContext = errors.New("cancel graceful shutdown's context")

View File

@@ -1,16 +1,28 @@
package gotenberg
import (
"path/filepath"
"regexp"
"sort"
"strconv"
)
type numberLoc int
const (
numberNone numberLoc = iota
numberPrefix
numberExtSuffix // number right before extension.
numberSuffix // trailing number with no extension.
)
// AlphanumericSort implements sort.Interface and helps to sort strings
// alphanumerically by either a numeric prefix or, if missing, a numeric
// suffix.
//
// See: https://github.com/gotenberg/gotenberg/issues/805.
// See:
// https://github.com/gotenberg/gotenberg/issues/805.
// https://github.com/gotenberg/gotenberg/issues/1287.
type AlphanumericSort []string
func (s AlphanumericSort) Len() int {
@@ -22,20 +34,39 @@ func (s AlphanumericSort) Swap(i, j int) {
}
func (s AlphanumericSort) Less(i, j int) bool {
numI, restI := extractNumber(s[i])
numJ, restJ := extractNumber(s[j])
numI, restI, locI := extractNumber(s[i])
numJ, restJ, locJ := extractNumber(s[j])
// If both strings contain a number, compare them numerically.
// Both have a number.
if numI != -1 && numJ != -1 {
if numI != numJ {
return numI < numJ
// Both prefix numbers: numeric first, then rest.
if locI == numberPrefix && locJ == numberPrefix {
if numI != numJ {
return numI < numJ
}
return restI < restJ
}
// If the numbers are equal, compare the "rest" strings.
return restI < restJ
// Both are suffix-ish (right-before-ext or trailing): rest first, then
// number.
if locI != numberPrefix && locJ != numberPrefix {
if restI != restJ {
return restI < restJ
}
if numI != numJ {
return numI < numJ
}
return s[i] < s[j]
}
// Mixed: one prefix, one not.
if restI != restJ {
return restI < restJ
}
return locI == numberPrefix
}
// If one contains a number and the other doesn't, the one with the number
// comes first.
// One has a number: it comes first.
if numI != -1 {
return true
}
@@ -43,41 +74,29 @@ func (s AlphanumericSort) Less(i, j int) bool {
return false
}
// Neither has a number; fall back to lexicographical order.
// Neither has a number: plain lexicographic.
return s[i] < s[j]
}
// extractNumber attempts to extract a numeric portion from the filename.
// It first checks for a numeric prefix (digits at the beginning).
// If none is found, it next attempts to match a number immediately before the
// extension (for filenames such as "sample1_1.pdf").
// If that fails, it then attempts a trailing numeric pattern.
// If no number is found, it returns -1 and the original string.
func extractNumber(str string) (int, string) {
// Check for a numeric prefix.
func extractNumber(str string) (int, string, numberLoc) {
str = filepath.Base(str)
if matches := prefixRegexp.FindStringSubmatch(str); len(matches) > 2 {
if num, err := strconv.Atoi(matches[1]); err == nil {
return num, matches[2]
return num, matches[2], numberPrefix
}
}
// Check for a number immediately before an extension.
if matches := extensionSuffixRegexp.FindStringSubmatch(str); len(matches) > 3 {
if num, err := strconv.Atoi(matches[2]); err == nil {
// Remove the numeric block but keep the extension.
return num, matches[1] + matches[3]
return num, matches[1] + matches[3], numberExtSuffix
}
}
// Check for a trailing number (with no extension following).
if matches := suffixRegexp.FindStringSubmatch(str); len(matches) > 2 {
if num, err := strconv.Atoi(matches[2]); err == nil {
return num, matches[1]
return num, matches[1], numberSuffix
}
}
// No numeric portion found.
return -1, str
return -1, str, numberNone
}
// Regular expressions used by extractNumber.

View File

@@ -32,6 +32,12 @@ func TestAlphanumericSort(t *testing.T) {
values: []string{"245654773395259", "245654773395039", "245654773395149", "245654773394919", "245654773394369"},
expectedSort: []string{"245654773394369", "245654773394919", "245654773395039", "245654773395149", "245654773395259"},
},
{
// https://github.com/gotenberg/gotenberg/issues/1287.
scenario: "different basenames with numeric suffixes",
values: []string{"RIJNMOND-attach-Opdrachtbevestiging_P0007104.pdf", "Bundle-25029.pdf"},
expectedSort: []string{"Bundle-25029.pdf", "RIJNMOND-attach-Opdrachtbevestiging_P0007104.pdf"},
},
} {
t.Run(tc.scenario, func(t *testing.T) {
sort.Sort(AlphanumericSort(tc.values))

View File

@@ -26,7 +26,7 @@ func init() {
gotenberg.MustRegisterModule(new(Api))
}
// Api is a module which provides an HTTP server. Other modules may add routes,
// Api is a module that provides an HTTP server. Other modules may add routes,
// middlewares or health checks.
type Api struct {
port int
@@ -48,6 +48,7 @@ type Api struct {
externalMiddlewares []Middleware
healthChecks []health.CheckerOption
readyFn []func() error
asyncCounters []AsynchronousCounter
fs *gotenberg.FileSystem
logger *zap.Logger
srv *echo.Echo
@@ -60,7 +61,7 @@ type downloadFromConfig struct {
disable bool
}
// Router is a module interface which adds routes to the [Api].
// Router is a module interface that adds routes to the [Api].
type Router interface {
Routes() ([]Route, error)
}
@@ -83,17 +84,17 @@ type Route struct {
// Optional.
DisableLogging bool
// Handler is the function which handles the request.
// Handler is the function that handles the request.
// Required.
Handler echo.HandlerFunc
}
// MiddlewareProvider is a module interface which adds middlewares to the [Api].
// MiddlewareProvider is a module interface that adds middlewares to the [Api].
type MiddlewareProvider interface {
Middlewares() ([]Middleware, error)
}
// MiddlewareStack is a type which helps to determine in which stack the
// MiddlewareStack is a type that helps to determine in which stack the
// middlewares provided by the [MiddlewareProvider] modules should be located.
type MiddlewareStack uint32
@@ -103,7 +104,7 @@ const (
MultipartStack
)
// MiddlewarePriority is a type which helps to determine the execution order of
// MiddlewarePriority is a type that helps to determine the execution order of
// middlewares provided by the [MiddlewareProvider] modules in a stack.
type MiddlewarePriority uint32
@@ -115,7 +116,7 @@ const (
VeryHighPriority
)
// Middleware is a middleware which can be added to the [Api]'s middlewares
// Middleware is a middleware that can be added to the [Api]'s middlewares
// chain.
//
// middleware := Middleware{
@@ -157,7 +158,7 @@ type Middleware struct {
Handler echo.MiddlewareFunc
}
// HealthChecker is a module interface which allows adding health checks to the
// HealthChecker is a module interface that allows adding health checks to the
// API.
//
// See https://github.com/alexliesenfeld/health for more details.
@@ -166,6 +167,14 @@ type HealthChecker interface {
Ready() error
}
// AsynchronousCounter is a module interface that returns the number of active
// asynchronous requests.
//
// See https://github.com/gotenberg/gotenberg/issues/1022.
type AsynchronousCounter interface {
AsyncCount() int64
}
// Descriptor returns an [Api]'s module descriptor.
func (a *Api) Descriptor() gotenberg.ModuleDescriptor {
return gotenberg.ModuleDescriptor{
@@ -307,6 +316,17 @@ func (a *Api) Provision(ctx *gotenberg.Context) error {
a.readyFn = append(a.readyFn, healthChecker.Ready)
}
// Get asynchronous counters.
mods, err = ctx.Modules(new(AsynchronousCounter))
if err != nil {
return fmt.Errorf("get asynchronous counters: %w", err)
}
a.asyncCounters = make([]AsynchronousCounter, len(mods))
for i, asyncCounter := range mods {
a.asyncCounters[i] = asyncCounter.(AsynchronousCounter)
}
// Logger.
loggerProvider, err := ctx.Module(new(gotenberg.LoggerProvider))
if err != nil {
@@ -431,7 +451,7 @@ func (a *Api) Start() error {
}
}
// Check if the user wish to add logging entries related to the health
// Check if the user wishes to add logging entries related to the health
// check route.
if a.disableHealthCheckLogging {
disableLoggingForPaths = append(disableLoggingForPaths, "health")
@@ -442,6 +462,7 @@ func (a *Api) Start() error {
latencyMiddleware(),
rootPathMiddleware(a.rootPath),
traceMiddleware(a.traceHeader),
outputFilenameMiddleware(),
loggerMiddleware(a.logger, disableLoggingForPaths),
)
@@ -597,7 +618,28 @@ func (a *Api) StartupMessage() string {
// Stop stops the HTTP server.
func (a *Api) Stop(ctx context.Context) error {
return a.srv.Shutdown(ctx)
for {
count := int64(0)
for _, asyncCounter := range a.asyncCounters {
count += asyncCounter.AsyncCount()
}
select {
case <-ctx.Done():
return a.srv.Shutdown(ctx)
default:
a.logger.Debug(fmt.Sprintf("%d asynchronous requests", count))
if count > 0 {
time.Sleep(1 * time.Second)
continue
}
a.logger.Debug("no more asynchronous requests, continue with shutdown")
err := a.srv.Shutdown(ctx)
if err != nil {
return fmt.Errorf("shutdown: %w", err)
}
return gotenberg.ErrCancelGracefulShutdownContext
}
}
}
// Interface guards.

View File

@@ -409,6 +409,13 @@ func (ctx *Context) GeneratePath(extension string) string {
return fmt.Sprintf("%s/%s%s", ctx.dirPath, uuid.New().String(), extension)
}
// GeneratePathFromFilename generates a path within the context's working
// directory, using the given filename (with extension). It does not create
// a file.
func (ctx *Context) GeneratePathFromFilename(filename string) string {
return fmt.Sprintf("%s/%s", ctx.dirPath, filename)
}
// CreateSubDirectory creates a subdirectory within the context's working
// directory.
func (ctx *Context) CreateSubDirectory(dirName string) (string, error) {
@@ -506,7 +513,7 @@ func (ctx *Context) BuildOutputFile() (string, error) {
// OutputFilename returns the filename based on the given output path or the
// "Gotenberg-Output-Filename" header's value.
func (ctx *Context) OutputFilename(outputPath string) string {
filename := ctx.echoCtx.Request().Header.Get("Gotenberg-Output-Filename")
filename := ctx.echoCtx.Get("outputFilename").(string)
if filename == "" {
return filepath.Base(outputPath)

View File

@@ -1,3 +1,3 @@
// Package api provides a module which is an HTTP server. Other modules may
// Package api provides a module, which is an HTTP server. Other modules may
// add multipart/form-data routes, middlewares, and health checks.
package api

View File

@@ -27,7 +27,7 @@ type FormData struct {
}
// Validate returns nil or an error related to the [FormData] values, with a
// [SentinelHttpError] (status code 400, errors' details as message) wrapped
// [SentinelHttpError] (status code 400, errors' details as a message) wrapped
// inside.
//
// var foo string
@@ -96,7 +96,7 @@ func (form *FormData) Int(key string, target *int, defaultValue int) *FormData {
}
// MandatoryInt binds a form field to an int variable. It populates an
// error if the value is not int, is empty, or the "key" does not exist.
// error if the value is not int, or is empty, or the "key" does not exist.
//
// var foo int
//
@@ -116,7 +116,7 @@ func (form *FormData) Float64(key string, target *float64, defaultValue float64)
}
// MandatoryFloat64 binds a form field to a float64 variable. It populates
// an error if the is not float64, is empty, or the "key" does not exist.
// an error if the value is not float64, is empty, or the "key" does not exist.
//
// var foo float64
//
@@ -136,8 +136,8 @@ func (form *FormData) Duration(key string, target *time.Duration, defaultValue t
}
// MandatoryDuration binds a form field to a time.Duration variable. It
// populates an error if the value is not time.Duration, is empty, or the "key"
// does not exist.
// populates an error if the value is not time.Duration, or is empty, or the
// "key" does not exist.
//
// var foo time.Duration
//
@@ -146,7 +146,7 @@ func (form *FormData) MandatoryDuration(key string, target *time.Duration) *Form
return form.mustMandatoryField(key, target)
}
// Inches binds a form field to a float64 variable. It populates an error
// Inches bind a form field to a float64 variable. It populates an error
// if the value cannot be computed back to inches.
//
// var foo float64
@@ -303,7 +303,7 @@ func (form *FormData) Path(filename string, target *string) *FormData {
return form.path(filename, target)
}
// MandatoryPath binds the absolute path ofa form data file to a string
// MandatoryPath binds the absolute path of a form data file to a string
// variable. It populates an error if the file does not exist.
//
// var path string
@@ -348,7 +348,7 @@ func (form *FormData) MandatoryContent(filename string, target *string) *FormDat
return form.readFile(path, filename, target)
}
// Paths binds the absolute paths of form data files, according to a list of
// Paths bind the absolute paths of form data files, according to a list of
// file extensions, to a string slice variable.
//
// var paths []string
@@ -379,7 +379,7 @@ func (form *FormData) MandatoryPaths(extensions []string, target *[]string) *For
return form
}
// paths binds the absolute paths of form data files, according to a list of
// paths bind the absolute paths of form data files, according to a list of
// file extensions, to a string slice variable.
func (form *FormData) paths(extensions []string, target *[]string) *FormData {
for filename, path := range form.files {

View File

@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"net/http"
"path/filepath"
"strings"
"time"
@@ -86,7 +87,7 @@ func httpErrorHandler() echo.HTTPErrorHandler {
}
// latencyMiddleware sets the start time in the [echo.Context] under
// "startTime". Its value will be used later to calculate a request latency.
// "startTime". Its value will be used later to calculate request latency.
//
// startTime := c.Get("startTime").(time.Time)
func latencyMiddleware() echo.MiddlewareFunc {
@@ -109,7 +110,7 @@ func latencyMiddleware() echo.MiddlewareFunc {
// rootPath := c.Get("rootPath").(string)
// healthURI := fmt.Sprintf("%s/health", rootPath)
//
// // Skip the middleware if health check URI.
// // Skip the middleware if it's the health check URI.
// if c.Request().RequestURI == healthURI {
// // Call the next middleware in the chain.
// return next(c)
@@ -150,6 +151,25 @@ func traceMiddleware(header string) echo.MiddlewareFunc {
}
}
// outputFilenameMiddleware sets the output filename in the [echo.Context]
// under "outputFilename".
//
// outputFilename := c.Get("outputFilename").(string)
func outputFilenameMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
filename := c.Request().Header.Get("Gotenberg-Output-Filename")
// See https://github.com/gotenberg/gotenberg/issues/1227.
if filename != "" {
filename = filepath.Base(filename)
}
c.Set("outputFilename", filename)
// Call the next middleware in the chain.
return next(c)
}
}
}
// loggerMiddleware sets the logger in the [echo.Context] under "logger" and
// logs a synchronous request result.
//
@@ -241,7 +261,7 @@ func basicAuthMiddleware(username, password string) echo.MiddlewareFunc {
})
}
// contextMiddleware, a middleware for "multipart/form-data" requests, sets the
// contextMiddleware, middleware for "multipart/form-data" requests, sets the
// [Context] and related context.CancelFunc in the [echo.Context] under
// "context" and "cancel". If the process is synchronous, it also handles the
// result of a "multipart/form-data" request.
@@ -256,7 +276,7 @@ func contextMiddleware(fs *gotenberg.FileSystem, timeout time.Duration, bodyLimi
trace := c.Get("trace").(string)
// We create a context with a timeout so that underlying processes are
// able to stop early and handle correctly a timeout scenario.
// able to stop early and correctly handle a timeout scenario.
ctx, cancel, err := newContext(c, logger, fs, timeout, bodyLimit, downloadFromCfg, traceHeader, trace)
if err != nil {
cancel()

View File

@@ -54,7 +54,7 @@ func (ctx *ContextMock) SetFiles(files map[string]string) {
ctx.files = files
}
// SetCancelled sets if the context is cancelled or not.
// SetCancelled sets if the context is canceled or not.
//
// ctx := &api.ContextMock{Context: &api.Context{}}
// ctx.SetCancelled(true)
@@ -120,7 +120,7 @@ func (provider *MiddlewareProviderMock) Middlewares() ([]Middleware, error) {
return provider.MiddlewaresMock()
}
// HealthCheckerMock is mock for the [HealthChecker] interface.
// HealthCheckerMock is a mock for the [HealthChecker] interface.
type HealthCheckerMock struct {
ChecksMock func() ([]health.CheckerOption, error)
ReadyMock func() error

View File

@@ -12,6 +12,7 @@ import (
"github.com/chromedp/cdproto/fetch"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/cdproto/page"
"github.com/chromedp/cdproto/runtime"
"github.com/chromedp/chromedp"
"github.com/dlclark/regexp2"
@@ -38,6 +39,7 @@ type browserArguments struct {
hostResolverRules string
proxyServer string
wsUrlReadTimeout time.Duration
hyphenDataDirPath string
// Tasks specific.
allowList *regexp2.Regexp
@@ -78,21 +80,32 @@ func (b *chromiumBrowser) Start(logger *zap.Logger) error {
debug := &debugLogger{logger: logger}
b.userProfileDirPath = b.fs.NewDirPath()
// See https://github.com/gotenberg/gotenberg/issues/1293.
err := os.MkdirAll(b.userProfileDirPath, 0o755)
if err != nil {
return fmt.Errorf("could not create user profile directory: %w", err)
}
err = os.Symlink(b.arguments.hyphenDataDirPath, fmt.Sprintf("%s/hyphen-data", b.userProfileDirPath))
if err != nil {
return fmt.Errorf("create symlink to hyphen-data directory: %w", err)
}
opts := append(chromedp.DefaultExecAllocatorOptions[:],
chromedp.CombinedOutput(debug),
chromedp.ExecPath(b.arguments.binPath),
chromedp.NoSandbox,
// See:
// https://github.com/gotenberg/gotenberg/issues/327
// https://github.com/chromedp/chromedp/issues/904
chromedp.DisableGPU,
// See:
// https://github.com/puppeteer/puppeteer/issues/661
// https://github.com/puppeteer/puppeteer/issues/2410
chromedp.Flag("font-render-hinting", "none"),
chromedp.UserDataDir(b.userProfileDirPath),
// See https://github.com/gotenberg/gotenberg/issues/831.
chromedp.Flag("disable-pdf-tagging", true),
// See https://github.com/gotenberg/gotenberg/issues/1177.
chromedp.Flag("no-zygote", true),
chromedp.Flag("disable-dev-shm-usage", true),
// See https://github.com/gotenberg/gotenberg/issues/1293.
chromedp.Flag("disable-component-update", false),
)
if b.arguments.incognito {
@@ -133,7 +146,7 @@ func (b *chromiumBrowser) Start(logger *zap.Logger) error {
allocatorCtx, allocatorCancel := chromedp.NewExecAllocator(b.initialCtx, opts...)
ctx, cancel := chromedp.NewContext(allocatorCtx, chromedp.WithDebugf(debug.Printf))
err := chromedp.Run(ctx)
err = chromedp.Run(ctx)
if err != nil {
cancel()
allocatorCancel()
@@ -211,7 +224,7 @@ func (b *chromiumBrowser) Stop(logger *zap.Logger) error {
logger.Debug(fmt.Sprintf("'%s' Chromium's user profile directory removed", userProfileDirPath))
}
// Also remove Chromium specific files in the temporary directory.
// Also, remove Chromium-specific files in the temporary directory.
err = gotenberg.GarbageCollect(logger, os.TempDir(), []string{".org.chromium.Chromium", ".com.google.Chrome"}, expirationTime)
if err != nil {
logger.Error(err.Error())
@@ -271,12 +284,14 @@ func (b *chromiumBrowser) pdf(ctx context.Context, logger *zap.Logger, url, outp
userAgentOverride(logger, options.UserAgent),
navigateActionFunc(logger, url, options.SkipNetworkIdleEvent),
hideDefaultWhiteBackgroundActionFunc(logger, options.OmitBackground, options.PrintBackground),
forceExactColorsActionFunc(),
forceExactColorsActionFunc(logger, options.PrintBackground),
emulateMediaTypeActionFunc(logger, options.EmulatedMediaType),
waitDelayBeforePrintActionFunc(logger, b.arguments.disableJavaScript, options.WaitDelay),
waitForExpressionBeforePrintActionFunc(logger, b.arguments.disableJavaScript, options.WaitForExpression),
waitDelayBeforePrintActionFunc(logger, b.arguments.disableJavaScript, options.WaitDelay),
// PDF specific.
printToPdfActionFunc(logger, outputPath, options),
// Teardown.
page.Close(),
})
}
@@ -294,13 +309,15 @@ func (b *chromiumBrowser) screenshot(ctx context.Context, logger *zap.Logger, ur
userAgentOverride(logger, options.UserAgent),
navigateActionFunc(logger, url, options.SkipNetworkIdleEvent),
hideDefaultWhiteBackgroundActionFunc(logger, options.OmitBackground, true),
forceExactColorsActionFunc(),
forceExactColorsActionFunc(logger, true),
emulateMediaTypeActionFunc(logger, options.EmulatedMediaType),
waitDelayBeforePrintActionFunc(logger, b.arguments.disableJavaScript, options.WaitDelay),
waitForExpressionBeforePrintActionFunc(logger, b.arguments.disableJavaScript, options.WaitForExpression),
waitDelayBeforePrintActionFunc(logger, b.arguments.disableJavaScript, options.WaitDelay),
// Screenshot specific.
setDeviceMetricsOverride(logger, options.Width, options.Height),
captureScreenshotActionFunc(logger, outputPath, options),
// Teardown.
page.Close(),
})
}
@@ -314,7 +331,7 @@ func (b *chromiumBrowser) do(ctx context.Context, logger *zap.Logger, url string
return errors.New("context has no deadline")
}
// We validate the "main" URL against our allow / deny lists.
// We validate the "main" URL against our allowed / deny lists.
err := gotenberg.FilterDeadline(b.arguments.allowList, b.arguments.denyList, url, deadline)
if err != nil {
return fmt.Errorf("filter URL: %w", err)
@@ -329,7 +346,7 @@ func (b *chromiumBrowser) do(ctx context.Context, logger *zap.Logger, url string
taskCtx, taskCancel := chromedp.NewContext(timeoutCtx)
defer taskCancel()
// We validate all others requests against our allow / deny lists.
// We validate all other requests against our allowed / deny lists.
// If a request does not pass the validation, we make it fail. It also set
// the extra HTTP headers, if any.
// See https://github.com/gotenberg/gotenberg/issues/1011.

View File

@@ -26,7 +26,7 @@ func init() {
var (
// ErrInvalidEmulatedMediaType happens if the emulated media type is not
// "screen" nor "print". Empty value are allowed though.
// "screen" nor "print". Empty value is allowed, though.
ErrInvalidEmulatedMediaType = errors.New("invalid emulated media type")
// ErrInvalidEvaluationExpression happens if an evaluation expression
@@ -38,11 +38,11 @@ var (
ErrRpccMessageTooLarge = errors.New("rpcc message too large")
// ErrInvalidHttpStatusCode happens when the status code from the main page
// matches with one of the entry in [Options.FailOnHttpStatusCodes].
// matches with one of the entries in [Options.FailOnHttpStatusCodes].
ErrInvalidHttpStatusCode = errors.New("invalid HTTP status code")
// ErrInvalidResourceHttpStatusCode happens when the status code from one
// or more resources matches with one of the entry in
// or more resources matches with one of the entries in
// [Options.FailOnResourceHttpStatusCodes].
ErrInvalidResourceHttpStatusCode = errors.New("invalid resource HTTP status code")
@@ -68,12 +68,12 @@ var (
ErrInvalidPrinterSettings = errors.New("invalid printer settings")
// ErrPageRangesSyntaxError happens if the PdfOptions have an invalid page
// ranges.
// range.
ErrPageRangesSyntaxError = errors.New("page ranges syntax error")
)
// Chromium is a module which provides both an [Api] and routes for converting
// HTML document to PDF.
// Chromium is a module that provides both an [Api] and routes for converting
// an HTML document to PDF.
type Chromium struct {
autoStart bool
disableRoutes bool
@@ -128,15 +128,15 @@ type Options struct {
UserAgent string
// ExtraHttpHeaders are extra HTTP headers to send by Chromium while
// loading he HTML document.
// loading the HTML document.
ExtraHttpHeaders []ExtraHttpHeader
// EmulatedMediaType is the media type to emulate, either "screen" or
// "print".
EmulatedMediaType string
// OmitBackground hides default white background and allows generating PDFs
// with transparency.
// OmitBackground hides the default white background and allows generating
// PDFs with transparency.
OmitBackground bool
}
@@ -197,9 +197,9 @@ type PdfOptions struct {
// Page ranges to print, e.g., '1-5, 8, 11-13'. Empty means all pages.
PageRanges string
// HeaderTemplate is the HTML template of the header. It should be valid
// HTML markup with following classes used to inject printing values into
// them:
// HeaderTemplate is the HTML template of the header. It should be a valid
// HTML markup with the following classes used to inject printing values
// into them:
// - date: formatted print date
// - title: document title
// - url: document location
@@ -220,6 +220,10 @@ type PdfOptions struct {
// GenerateDocumentOutline defines whether the document outline should be
// embedded into the PDF.
GenerateDocumentOutline bool
// GenerateTaggedPdf defines whether to generate tagged (accessible)
// PDF.
GenerateTaggedPdf bool
}
// DefaultPdfOptions returns the default values for PdfOptions.
@@ -241,6 +245,7 @@ func DefaultPdfOptions() PdfOptions {
FooterTemplate: "<html><head></head><body></body></html>",
PreferCssPageSize: false,
GenerateDocumentOutline: false,
GenerateTaggedPdf: false,
}
}
@@ -338,7 +343,7 @@ type Api interface {
Screenshot(ctx context.Context, logger *zap.Logger, url, outputPath string, options ScreenshotOptions) error
}
// Provider is a module interface which exposes a method for creating an [Api]
// Provider is a module interface that exposes a method for creating an [Api]
// for other modules.
//
// func (m *YourModule) Provision(ctx *gotenberg.Context) error {
@@ -390,6 +395,11 @@ func (mod *Chromium) Provision(ctx *gotenberg.Context) error {
return errors.New("CHROMIUM_BIN_PATH environment variable is not set")
}
hyphenDataDirPath, ok := os.LookupEnv("CHROMIUM_HYPHEN_DATA_DIR_PATH")
if !ok {
return errors.New("CHROMIUM_HYPHEN_DATA_DIR_PATH environment variable is not set")
}
mod.args = browserArguments{
binPath: binPath,
incognito: flags.MustBool("chromium-incognito"),
@@ -400,6 +410,7 @@ func (mod *Chromium) Provision(ctx *gotenberg.Context) error {
hostResolverRules: flags.MustString("chromium-host-resolver-rules"),
proxyServer: flags.MustString("chromium-proxy-server"),
wsUrlReadTimeout: flags.MustDuration("chromium-start-timeout"),
hyphenDataDirPath: hyphenDataDirPath,
allowList: flags.MustRegexp("chromium-allow-list"),
denyList: flags.MustRegexp("chromium-deny-list"),
@@ -444,6 +455,11 @@ func (mod *Chromium) Validate() error {
return fmt.Errorf("chromium binary path does not exist: %w", err)
}
_, err = os.Stat(mod.args.hyphenDataDirPath)
if os.IsNotExist(err) {
return fmt.Errorf("chromium hyphen-data directory path does not exist: %w", err)
}
return nil
}
@@ -473,8 +489,8 @@ func (mod *Chromium) StartupMessage() string {
// Stop stops the current browser instance.
func (mod *Chromium) Stop(ctx context.Context) error {
// Block until the context is done so that other module may gracefully stop
// before we do a shutdown.
// Block until the context is done so that another module may gracefully
// stop before we do a shutdown.
mod.logger.Debug("wait for the end of grace duration")
<-ctx.Done()

View File

@@ -72,10 +72,10 @@ func listenForEventRequestPaused(ctx context.Context, logger *zap.Logger, option
var extraHttpHeadersToSet []ExtraHttpHeader
if len(options.extraHttpHeaders) > 0 {
// The user want to set extra HTTP headers.
// The user wants to set extra HTTP headers.
// First, we have to check if at least one header has to be
// set for current request.
// set for the current request.
for _, header := range options.extraHttpHeaders {
if header.Scope == nil {
// Non-scoped header.
@@ -147,8 +147,8 @@ type eventResponseReceivedOptions struct {
invalidResourceHttpStatusCodeMu *sync.RWMutex
}
// listenForEventResponseReceived listens for an invalid HTTP status code that
// is returned by the main page or by one or more resources.
// listenForEventResponseReceived listens for an invalid HTTP status code
// returned by the main page or by one or more resources.
// See:
// https://github.com/gotenberg/gotenberg/issues/613.
// https://github.com/gotenberg/gotenberg/issues/1021.

View File

@@ -25,7 +25,7 @@ import (
)
// FormDataChromiumOptions creates [Options] from the form data. Fallback to
// default value if the considered key is not present.
// the default value if the considered key is not present.
func FormDataChromiumOptions(ctx *api.Context) (*api.FormData, Options) {
defaultOptions := DefaultOptions()
@@ -194,7 +194,7 @@ func FormDataChromiumOptions(ctx *api.Context) (*api.FormData, Options) {
}
// FormDataChromiumPdfOptions creates [PdfOptions] from the form data. Fallback to
// default value if the considered key is not present.
// the default value if the considered key is not present.
func FormDataChromiumPdfOptions(ctx *api.Context) (*api.FormData, PdfOptions) {
form, options := FormDataChromiumOptions(ctx)
defaultPdfOptions := DefaultPdfOptions()
@@ -207,6 +207,7 @@ func FormDataChromiumPdfOptions(ctx *api.Context) (*api.FormData, PdfOptions) {
headerTemplate, footerTemplate string
preferCssPageSize bool
generateDocumentOutline bool
generateTaggedPdf bool
)
form.
@@ -224,7 +225,8 @@ func FormDataChromiumPdfOptions(ctx *api.Context) (*api.FormData, PdfOptions) {
Content("header.html", &headerTemplate, defaultPdfOptions.HeaderTemplate).
Content("footer.html", &footerTemplate, defaultPdfOptions.FooterTemplate).
Bool("preferCssPageSize", &preferCssPageSize, defaultPdfOptions.PreferCssPageSize).
Bool("generateDocumentOutline", &generateDocumentOutline, defaultPdfOptions.GenerateDocumentOutline)
Bool("generateDocumentOutline", &generateDocumentOutline, defaultPdfOptions.GenerateDocumentOutline).
Bool("generateTaggedPdf", &generateTaggedPdf, defaultPdfOptions.GenerateTaggedPdf)
pdfOptions := PdfOptions{
Options: options,
@@ -243,13 +245,14 @@ func FormDataChromiumPdfOptions(ctx *api.Context) (*api.FormData, PdfOptions) {
FooterTemplate: footerTemplate,
PreferCssPageSize: preferCssPageSize,
GenerateDocumentOutline: generateDocumentOutline,
GenerateTaggedPdf: generateTaggedPdf,
}
return form, pdfOptions
}
// FormDataChromiumScreenshotOptions creates [ScreenshotOptions] from the form
// data. Fallback to default value if the considered key is not present.
// data. Fallback to the default value if the considered key is not present.
func FormDataChromiumScreenshotOptions(ctx *api.Context) (*api.FormData, ScreenshotOptions) {
form, options := FormDataChromiumOptions(ctx)
defaultScreenshotOptions := DefaultScreenshotOptions()
@@ -483,7 +486,7 @@ func convertMarkdownRoute(chromium Api, engine gotenberg.PdfEngine) api.Route {
}
// screenshotMarkdownRoute returns an [api.Route] which can take a screenshot
// from markdown files.
// from Markdown files.
func screenshotMarkdownRoute(chromium Api) api.Route {
return api.Route{
Method: http.MethodPost,
@@ -522,7 +525,7 @@ func screenshotMarkdownRoute(chromium Api) api.Route {
}
func markdownToHtml(ctx *api.Context, inputPath string, markdownPaths []string) (string, error) {
// We have to convert each markdown file referenced in the HTML
// We have to convert each Markdown file referenced in the HTML
// file to... HTML. Thanks to the "html/template" package, we are
// able to provide the "toHTML" function which the user may call
// directly inside the HTML file.
@@ -598,6 +601,9 @@ func markdownToHtml(ctx *api.Context, inputPath string, markdownPaths []string)
func convertUrl(ctx *api.Context, chromium Api, engine gotenberg.PdfEngine, url string, options PdfOptions, mode gotenberg.SplitMode, pdfFormats gotenberg.PdfFormats, metadata map[string]interface{}) error {
outputPath := ctx.GeneratePath(".pdf")
// See https://github.com/gotenberg/gotenberg/issues/1130.
filename := ctx.OutputFilename(outputPath)
outputPath = ctx.GeneratePathFromFilename(filename)
err := chromium.Pdf(ctx, ctx.Log(), url, outputPath, options)
err = handleChromiumError(err, options.Options)

View File

@@ -24,7 +24,7 @@ type streamReader struct {
// Read a chunk of the stream.
func (reader *streamReader) Read(p []byte) (n int, err error) {
if reader.r != nil {
// Continue reading from buffer.
// Continue reading from the buffer.
return reader.read(p)
}

View File

@@ -49,9 +49,8 @@ func printToPdfActionFunc(logger *zap.Logger, outputPath string, options PdfOpti
WithPageRanges(pageRanges).
WithPreferCSSPageSize(options.PreferCssPageSize).
WithGenerateDocumentOutline(options.GenerateDocumentOutline).
// Does not seem to work.
// See https://github.com/gotenberg/gotenberg/issues/831.
WithGenerateTaggedPDF(false)
// See https://github.com/gotenberg/gotenberg/issues/1210.
WithGenerateTaggedPDF(options.GenerateTaggedPdf)
hasCustomHeaderFooter := options.HeaderTemplate != DefaultPdfOptions().HeaderTemplate ||
options.FooterTemplate != DefaultPdfOptions().FooterTemplate
@@ -331,7 +330,7 @@ func navigateActionFunc(logger *zap.Logger, url string, skipNetworkIdleEvent boo
return func(ctx context.Context) error {
logger.Debug(fmt.Sprintf("navigate to '%s'", url))
_, _, _, err := page.Navigate(url).Do(ctx)
_, _, _, _, err := page.Navigate(url).Do(ctx)
if err != nil {
return fmt.Errorf("navigate to '%s': %w", url, err)
}
@@ -392,26 +391,30 @@ func hideDefaultWhiteBackgroundActionFunc(logger *zap.Logger, omitBackground, pr
}
}
func forceExactColorsActionFunc() chromedp.ActionFunc {
func forceExactColorsActionFunc(logger *zap.Logger, printBackground bool) chromedp.ActionFunc {
return func(ctx context.Context) error {
// See:
// https://github.com/gotenberg/gotenberg/issues/354
// https://github.com/puppeteer/puppeteer/issues/2685
// https://github.com/chromedp/chromedp/issues/520
script := `
(() => {
const css = 'html { -webkit-print-color-adjust: exact !important; }';
css := "html { -webkit-print-color-adjust: exact !important; }"
if !printBackground {
// The -webkit-print-color-adjust: exact CSS property forces the
// print of the background, whatever the printToPDF args.
// See https://github.com/gotenberg/gotenberg/issues/1154.
additionalCss := "html, body { background: none !important; }"
logger.Debug(fmt.Sprintf("inject %s as printBackground is %t", additionalCss, printBackground))
css += additionalCss
}
script := fmt.Sprintf(`
(() => {
const css = '%s';
const style = document.createElement('style');
style.type = 'text/css';
style.appendChild(document.createTextNode(css));
document.head.appendChild(style);
})();
`
`, css)
evaluate := chromedp.Evaluate(script, nil)
err := evaluate.Do(ctx)
if err == nil {
return nil
}

View File

@@ -142,15 +142,15 @@ func (engine *ExifTool) WriteMetadata(ctx context.Context, logger *zap.Logger, m
fileMetadata[0].SetStrings(key, val)
case []interface{}:
// See https://github.com/gotenberg/gotenberg/issues/1048.
strings := make([]string, len(val))
strs := make([]string, len(val))
for i, entry := range val {
if str, ok := entry.(string); ok {
strings[i] = str
strs[i] = str
continue
}
return fmt.Errorf("write PDF metadata with ExifTool: %s %+v %s %w", key, val, reflect.TypeOf(val), gotenberg.ErrPdfEngineMetadataValueNotSupported)
}
fileMetadata[0].SetStrings(key, strings)
fileMetadata[0].SetStrings(key, strs)
case bool:
fileMetadata[0].SetString(key, fmt.Sprintf("%t", val))
case int:

View File

@@ -24,23 +24,23 @@ func init() {
}
var (
// ErrInvalidPdfFormats happens if the PDF formats option cannot be handled
// by LibreOffice.
// ErrInvalidPdfFormats happens if LibreOffice cannot handle the PDF
// formats option.
ErrInvalidPdfFormats = errors.New("invalid PDF formats")
// ErrUnoException happens when unoconverter returns an exit code 5.
// ErrUnoException happens when unoconverter returns exit code 5.
ErrUnoException = errors.New("uno exception")
// ErrRuntimeException happens when unoconverter returns an exit code 6.
// ErrRuntimeException happens when unoconverter returns exit code 6.
ErrRuntimeException = errors.New("uno exception")
// ErrCoreDumped happens randomly; sometime a conversion will work as
// ErrCoreDumped happens randomly; sometimes a conversion will work as
// expected, and some other time the same conversion will fail.
// See https://github.com/gotenberg/gotenberg/issues/639.
ErrCoreDumped = errors.New("core dumped")
)
// Api is a module which provides a [Uno] to interact with LibreOffice.
// Api is a module that provides a [Uno] to interact with LibreOffice.
type Api struct {
autoStart bool
args libreOfficeArguments
@@ -56,10 +56,10 @@ type Options struct {
// Password specifies the password for opening the source file.
Password string
// Landscape allows to change the orientation of the resulting PDF.
// Landscape allows changing the orientation of the resulting PDF.
Landscape bool
// PageRanges allows to select the pages to convert.
// PageRanges allows selecting the pages to convert.
PageRanges string
// UpdateIndexes specifies whether to update the indexes before conversion,
@@ -83,7 +83,7 @@ type Options struct {
// Named Destination.
ExportBookmarksToPdfDestination bool
// ExportPlaceholders exports the placeholders fields visual markings only.
// ExportPlaceholders exports the placeholder fields visual markings only.
// The exported placeholder is ineffective.
ExportPlaceholders bool
@@ -94,15 +94,16 @@ type Options struct {
// Notes pages are available in Impress documents only.
ExportNotesPages bool
// ExportOnlyNotesPages specifies, if the property ExportNotesPages is set
// to true, if only notes pages are exported to PDF.
// ExportOnlyNotesPages specifies if the property ExportNotesPages is set
// to true if only notes pages are exported to PDF.
ExportOnlyNotesPages bool
// ExportNotesInMargin specifies if notes in margin are exported to PDF.
// ExportNotesInMargin specifies if notes in the margin are exported to
// PDF.
ExportNotesInMargin bool
// ConvertOooTargetToPdfTarget specifies that the target documents with
// .od[tpgs] extension, will have that extension changed to .pdf when the
// .od[tpgs] extension will have that extension changed to .pdf when the
// link is exported to PDF. The source document remains untouched.
ConvertOooTargetToPdfTarget bool
@@ -190,7 +191,7 @@ type Uno interface {
Extensions() []string
}
// Provider is a module interface which exposes a method for creating a
// Provider is a module interface that exposes a method for creating a
// [Uno] for other modules.
//
// func (m *YourModule) Provision(ctx *gotenberg.Context) error {
@@ -300,8 +301,8 @@ func (a *Api) StartupMessage() string {
// Stop stops the current browser instance.
func (a *Api) Stop(ctx context.Context) error {
// Block until the context is done so that other module may gracefully stop
// before we do a shutdown.
// Block until the context is done so that another module may gracefully
// stop before we do a shutdown.
a.logger.Debug("wait for the end of grace duration")
<-ctx.Done()

View File

@@ -4,16 +4,13 @@ import (
"context"
"errors"
"fmt"
"io"
"net"
"os"
"path/filepath"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/google/uuid"
"go.uber.org/zap"
"github.com/gotenberg/gotenberg/v8/pkg/gotenberg"
@@ -200,7 +197,7 @@ func (p *libreOfficeProcess) Stop(logger *zap.Logger) error {
logger.Debug(fmt.Sprintf("'%s' LibreOffice's user profile directory removed", userProfileDirPath))
}
// Also remove LibreOffice specific files in the temporary directory.
// Also, remove LibreOffice specific files in the temporary directory.
err = gotenberg.GarbageCollect(logger, os.TempDir(), []string{"OSL_PIPE", ".tmp"}, expirationTime)
if err != nil {
logger.Error(err.Error())
@@ -333,11 +330,6 @@ func (p *libreOfficeProcess) pdf(ctx context.Context, logger *zap.Logger, inputP
)
}
inputPath, err := nonBasicLatinCharactersGuard(logger, inputPath)
if err != nil {
return fmt.Errorf("non-basic latin characters guard: %w", err)
}
args = append(args, "--output", outputPath, inputPath)
cmd, err := gotenberg.CommandContext(ctx, logger, p.arguments.unoBinPath, args...)
@@ -353,10 +345,10 @@ func (p *libreOfficeProcess) pdf(ctx context.Context, logger *zap.Logger, inputP
}
// LibreOffice's errors are not explicit.
// For instance, an exit code 5 may be explained by a malformed page
// ranges, but also by a not required password.
// For instance, exit code 5 may be explained by a malformed page range
// but also by a not required password.
// We may want to retry in case of a core dumped event.
// We may want to retry in case of a core-dumped event.
// See https://github.com/gotenberg/gotenberg/issues/639.
if strings.Contains(err.Error(), "core dumped") {
return ErrCoreDumped
@@ -374,65 +366,6 @@ func (p *libreOfficeProcess) pdf(ctx context.Context, logger *zap.Logger, inputP
return fmt.Errorf("convert to PDF: %w", err)
}
// LibreOffice cannot convert a file with a name containing non-basic Latin
// characters.
// See:
// https://github.com/gotenberg/gotenberg/issues/104
// https://github.com/gotenberg/gotenberg/issues/730
func nonBasicLatinCharactersGuard(logger *zap.Logger, inputPath string) (string, error) {
hasNonBasicLatinChars := func(str string) bool {
for _, r := range str {
// Check if the character is outside basic Latin.
if r != '.' && (r < ' ' || r > '~') {
return true
}
}
return false
}
filename := filepath.Base(inputPath)
if !hasNonBasicLatinChars(filename) {
logger.Debug("no non-basic latin characters in filename, skip copy")
return inputPath, nil
}
logger.Warn("non-basic latin characters in filename, copy to a file with a valid filename")
basePath := filepath.Dir(inputPath)
ext := filepath.Ext(inputPath)
newInputPath := filepath.Join(basePath, fmt.Sprintf("%s%s", uuid.NewString(), ext))
in, err := os.Open(inputPath)
if err != nil {
return "", fmt.Errorf("open file: %w", err)
}
defer func() {
err := in.Close()
if err != nil {
logger.Error(fmt.Sprintf("close file: %s", err))
}
}()
out, err := os.Create(newInputPath)
if err != nil {
return "", fmt.Errorf("create new file: %w", err)
}
defer func() {
err := out.Close()
if err != nil {
logger.Error(fmt.Sprintf("close new file: %s", err))
}
}()
_, err = io.Copy(out, in)
if err != nil {
return "", fmt.Errorf("copy file to new file: %w", err)
}
return newInputPath, nil
}
// Interface guards.
var (
_ gotenberg.Process = (*libreOfficeProcess)(nil)

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