Compare commits

..

56 Commits

Author SHA1 Message Date
github-actions[bot] 496614b067 chore: release 1.21.3 2026-09-26 16:30:44 +00:00
Charles Gauthereau 84f223c5be Merge pull request #113 from Portabase/fix/crypto-issue
fix: Agent panics with rustls CryptoProvider
2026-09-26 18:28:33 +02:00
Charles Gauthereau e1e649791e fix: Agent panics with rustls CryptoProvider 2026-09-26 18:11:19 +02:00
Charles Gauthereau 82c9b0aee0 Merge pull request #111 from Portabase/fix/license
fix: LICENSE File and Cargo.toml [skip-release]
2026-09-23 09:10:37 +02:00
charles-gauthereau 33b298a4e6 fix: LICENSE File and Cargo.toml 2026-09-23 09:06:48 +02:00
github-actions[bot] a2bd4d1572 chore: release 1.21.2 2026-09-22 12:10:46 +00:00
Charles Gauthereau 0e04cffc76 Merge pull request #109 from Portabase/fix/binaries
fix: binaries assets
2026-09-22 14:08:32 +02:00
charles-gauthereau 71e2473167 fix: scripts 2026-09-22 13:45:49 +02:00
charles-gauthereau 8a29f6b25d fix: Dockerfile 2026-09-22 13:43:53 +02:00
charles-gauthereau e05b28176c fix: binaries assets 2026-09-22 13:24:54 +02:00
charles-gauthereau 3c060fe150 fix: binaries assets 2026-09-22 12:37:13 +02:00
github-actions[bot] d42c31f3dc chore: release 1.21.1 2026-09-17 11:43:39 +00:00
Charles GTE 84673373a7 Merge pull request #107 from Portabase/fix/mongodb-options
fix: mongodb-options
2026-09-17 13:41:27 +02:00
Charles GTE 6f8a5c4228 fix: mongodb options 2026-09-17 11:20:16 +02:00
charles-gauthereau c5806a6ea4 fix: refactoring 2026-09-17 10:47:32 +02:00
Charles GTE c241020542 fix: mongodb options 2026-09-17 10:13:58 +02:00
github-actions[bot] e0bc6556aa chore: release 1.21.0 2026-09-14 13:11:26 +00:00
Charles GTE 947cb9bed7 Merge pull request #104 from Portabase/dev
Dev
2026-09-14 15:09:04 +02:00
Charles GTE b5d0035a3b Merge pull request #106 from Portabase/poc/hmac
fix: openssl windows
2026-09-14 14:52:26 +02:00
Charles GTE d52c328a99 fix: refactoring 2026-09-14 14:51:58 +02:00
Charles GTE 9b79ac4850 Merge branch 'refs/heads/dev' into poc/hmac
# Conflicts:
#	Cargo.lock
2026-09-14 14:51:22 +02:00
Charles GTE 6e50718b65 fix: tests 2026-09-14 14:30:11 +02:00
Charles GTE ee5ed81d48 fix: tests 2026-09-14 14:12:29 +02:00
Charles GTE df078b6202 Merge pull request #105 from Portabase/feat/sftp-storage
feat: sftp-storage
2026-09-14 10:55:40 +02:00
Charles GTE 24e3e3098d chore: update packages 2026-09-13 17:25:13 +02:00
Charles GTE f6e1a0df98 fix: refactoring 2026-09-12 21:15:04 +02:00
Charles GTE 49366ee24e refactor(storage): generic rclone config builder and shared obscure util 2026-09-12 21:10:50 +02:00
Charles GTE 012a984973 fix(storage): reject line breaks in sftp host/username; drop unused import 2026-09-12 21:02:28 +02:00
Charles GTE 6d1d7c6891 fix: refactoring 2026-09-12 18:15:45 +02:00
Charles GTE c70cde8a9c feat(storage): sftp provider over rclone rcat 2026-09-12 17:57:04 +02:00
Charles GTE c353443bdd feat(storage): sftp config model and rclone-config builder 2026-09-12 17:57:04 +02:00
Charles GTE 9f9dedfe87 feat: rclone-privider (#103)
* build: install rclone 1.75.1 in agent images

* build: exclude target/ and local artifacts from the docker context

* feat(storage): add rclone config model and validation helpers

* feat(storage): stream backups into rclone rcat

* fix(storage): abort truncated rclone uploads and strengthen stderr test

* feat(storage): add RcloneProvider upload path

* fix(storage): bound rclone timeouts, detect restore truncation, track sdd workspace

* fix(storage): block virtual and non-viable rclone backends

* fix: refactoring
2026-09-12 17:09:57 +02:00
Charles GTE 9bb830327e fix: refactoring 2026-09-10 22:55:47 +02:00
Charles GTE 31e55a7b4f fix(storage): block virtual and non-viable rclone backends 2026-09-10 22:38:08 +02:00
Charles GTE 576c055092 fix(storage): bound rclone timeouts, detect restore truncation, track sdd workspace 2026-09-10 22:38:08 +02:00
Charles GTE ba83b6b2b7 feat(storage): add RcloneProvider upload path 2026-09-10 22:38:07 +02:00
Charles GTE ea356ed54f fix(storage): abort truncated rclone uploads and strengthen stderr test 2026-09-10 22:37:37 +02:00
Charles GTE b222b13934 feat(storage): stream backups into rclone rcat 2026-09-10 22:37:09 +02:00
Charles GTE 9409f0ff25 feat(storage): add rclone config model and validation helpers 2026-09-10 22:37:00 +02:00
Charles GTE 59312215e9 build: exclude target/ and local artifacts from the docker context 2026-09-10 22:36:46 +02:00
Charles GTE 3ff360a971 build: install rclone 1.75.1 in agent images 2026-09-10 22:36:38 +02:00
Théo LAGACHE cc1703592e poc 2026-09-09 11:57:56 +02:00
github-actions[bot] 5f92297108 chore: release 1.20.1 2026-09-03 15:41:20 +00:00
Charles GTE d1821f7045 Merge pull request #102 from Portabase/fix/cron-crash
fix: cron crash for databases setup from dashboard
2026-09-03 17:38:53 +02:00
charles-gauthereau 0fe4d50cbd fix: docker-compose.yml 2026-09-03 17:38:35 +02:00
charles-gauthereau 1f29466a28 fix: cron crash for databases setup from dashboard 2026-09-03 17:22:03 +02:00
github-actions[bot] b74aaa0bbc chore: release 1.20.0 2026-08-28 15:42:27 +00:00
Charles GTE 7b5e5b2c78 Merge pull request #101 from Portabase/feat/retry-system
feat: retry-system
2026-08-28 17:40:20 +02:00
charles-gauthereau 99f1ef2081 fix: refactoring 2026-08-28 17:25:30 +02:00
charles-gauthereau 42c3c5945a fix: refactoring 2026-08-28 17:06:23 +02:00
charles-gauthereau db0f87c2e9 Merge branch 'main' into feat/retry-system 2026-08-28 16:54:51 +02:00
charles-gauthereau 87f33af772 fix: wire retry env vars into helm configmap, dedupe terminal retry log
helm/templates/env-configmap.yaml never listed RETRY_ATTEMPTS and
RETRY_BACKOFF_MS even though values.yaml gained them, so --set
env.RETRY_ATTEMPTS=N was silently ignored by Kubernetes deployments.
Add both keys in the same explicit style as the existing entries.

src/utils/retry.rs logged its own "failed after N attempts" error on
exhaustion, on top of the terminal log each call site already writes,
producing two error entries per failure. Worse, it changed a log
level: FileLock::acquire's "backup_already_in_progress" bails through
the combinator, which now logged it as error before runner.rs got a
chance to reclassify it as the routine warn it always was. A manual
backup colliding with a scheduled one would show up as a hard error
on the dashboard instead of the harmless warn it used to be, breaking
the "fails exactly as it does today" guarantee for job records.

Drop the combinator's terminal error log and give download_backup its
own terminal error log so all three call sites (runner, uploader,
downloader) own their failure logging uniformly. Update the two tests
that asserted the removed message to assert the new behavior instead.
2026-08-27 22:46:49 +02:00
charles-gauthereau b6a120fcbf feat: retry the restore backup download
Extracts the download body to download_once and makes download_backup a
retry wrapper around it. This path had no retry at all before, so a
single dropped connection failed the whole restore job.

Retrying is safe because File::create truncates and the target filename
is derived from Content-Disposition or the URL, so it is stable across
attempts. There is no Range resume: a download that fails at 90% starts
over.
2026-08-27 19:01:10 +02:00
charles-gauthereau 5298d82576 feat: retry storage uploads
Wraps provider.upload in the retry combinator. No provider changes are
needed: each one builds its upload stream from the file on disk inside
upload(), so every attempt gets a fresh handle and a fresh nonce.

Result<UploadResult, UploadResult> is collapsed with an or-pattern so
the last attempt's error and metadata survive into the existing failure
branch. A missing backup file short-circuits into Err rather than
returning early, which skips the retry without skipping the
backup_upload_status(failed) call that closes the server-side record.

backup_upload_init and backup_upload_status are left unwrapped; they
are control-plane calls, not storage uploads.
2026-08-27 18:53:06 +02:00
charles-gauthereau b0da2e40a3 feat: retry the database backup
Each attempt now dumps into its own tmp_path/attempt-{n} directory,
which is removed when the attempt fails. Without the per-attempt
directory pg_dump -Fd would refuse every retry, because it will not
write into a directory a previous attempt left behind; removing it on
failure keeps peak disk at one attempt's artifacts rather than five.

A backup blocked by a concurrent job is retried before surfacing the
same backup_already_in_progress code, since FileLock reports it as an
ordinary error and the combinator cannot tell it apart.

Reshapes retry()'s bound from the native AsyncFnMut sugar to the
classic F: FnMut(u32) -> Fut, Fut: Future<Output = Result<T, E>> + Send
shape (the pattern tokio-retry and backoff both use). AsyncFnMut's
produced future is a lifetime-quantified associated type
(F::CallRefFuture<'_>) that cannot be named or bounded as Send on
stable Rust, so wiring a retried call through it into a future that
eventually gets polled inside tokio::spawn (dispatcher.rs, via
execute_backup) made rustc's opaque-type Send inference fail with
"implementation of Send is not general enough" at the spawn site,
several call layers away from the actual retry call. Naming Fut as its
own type parameter lets Send be asserted on it directly instead, which
resolves cleanly. The combinator's control flow, log messages, and
formats are unchanged; only the bound and the call sites' closure
shape (async |x| { } becomes |x| async { }, with shared references
bound outside a move closure so the inner async move block only moves
Copy references, not the originals) are affected.
2026-08-27 18:39:41 +02:00
charles-gauthereau 55e20d48e7 feat: configurable retry policy and combinator
Adds RETRY_ATTEMPTS (3..=5, default 3) and RETRY_BACKOFF_MS
(100..=30000, default 1000) to Settings, validated with the same
panic-on-invalid contract as POOLING and CHUNK_SIZE_MB.

The combinator logs every failed attempt and any late success through
the JobLogger it borrows, so retries reach the server on the existing
job-log path with no API change. It borrows rather than clones the Arc
so Arc::try_unwrap in the backup executor keeps working. Backoff is
exponential with equal jitter, because the uploader retries storages
concurrently and would otherwise retry them in lockstep.
2026-08-27 18:13:17 +02:00
327 changed files with 3320 additions and 1485 deletions
+3 -5
View File
@@ -1,11 +1,9 @@
# Git
.git
.gitignore
# MD files
CHANGELOG.md
README.md
RELEASE.md
#IDE configurations
.idea
target
dump.rdb
.superpowers
-15
View File
@@ -44,21 +44,6 @@ jobs:
- name: Cache cargo build
uses: Swatinem/rust-cache@v2
- name: Cache vcpkg installed packages
uses: actions/cache@v4
with:
path: C:\vcpkg\installed
key: vcpkg-openssl-x64-windows-v1
- name: Install OpenSSL (x64) via vcpkg
shell: pwsh
run: |
# windows-latest ships vcpkg preinstalled; the install is a no-op when the
# package is restored from cache.
& "$env:VCPKG_INSTALLATION_ROOT\vcpkg.exe" install openssl:x64-windows
'VCPKG_ROOT=C:\vcpkg' | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
'OPENSSL_DIR=C:\vcpkg\installed\x64-windows' | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- name: Build (cargo release)
shell: pwsh
run: cargo build --release --bin app
+2 -1
View File
@@ -6,5 +6,6 @@
.env
.claude
/docs
.superpowers
+1 -1
View File
@@ -27,5 +27,5 @@ keywords:
- self-hosted
- portabase
license: Apache-2.0
version: 1.19.2
version: 1.21.3
date-released: '2026-02-24'
Generated
+1216 -1354
View File
File diff suppressed because it is too large Load Diff
+6 -3
View File
@@ -1,7 +1,8 @@
[package]
name = "portabase-agent"
version = "1.19.2"
version = "1.21.3"
edition = "2024"
license = "Apache-2.0"
[dependencies]
redis = { version = "1.0.2", features = ["aio", "tokio-comp"] }
@@ -19,10 +20,11 @@ log = "0.4.29"
toml = "0.9.10"
reqwest = { version = "0.13.1", features = ["json", "blocking", "multipart", "stream", "query"] }
anyhow = "1.0.100"
tokio = { version = "1.49.0", features = ["rt", "rt-multi-thread", "macros", "fs"] }
tokio = { version = "1.49.0", features = ["rt", "rt-multi-thread", "macros", "fs", "process", "io-util"] }
async-trait = "0.1.89"
tempfile = "3.24.0"
openssl = "0.10.75"
hmac = "0.12"
sha2 = "0.10"
hex = "0.4.3"
flate2 = "1.1.5"
tar = "0.4.44"
@@ -59,6 +61,7 @@ postgres = "0.19.12"
url = "2.5.8"
percent-encoding = "2.3.2"
bollard = "0.20.0"
rustls = "0.23"
[dev-dependencies]
tokio = { version = "1", features = ["full"] }
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2024 Portabase
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
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.

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