Skip to content

Restow 0.2.2

Choose a tag to compare

@github-actions github-actions released this 06 Oct 19:10
· 529 commits to main since this release
1db6364

Restow 0.2.2. Released 2026-10-06, channel beta.

Beta release. Run it alongside your existing backups, not as your only one, until
you have verified restores against your own data.

Summary

Restow 0.2.2 lets every Microsoft 365 source connect either through the consent
invitation or through a Graph app of its own, connects the tenant the backup app lives
in without a consent link, fixes the Hetzner Object Storage preset and the Object Lock
detection, and adds an alpha channel for test builds to the updater tab. Updating needs
no migration and no manual step; read the Upgrade Notes if you want to test alpha builds.

Breaking Changes

None.

Added

Microsoft 365

  • A Graph app of your own for a source (all editions). Besides the consent
    invitation with the shared backup app, a source can be connected through an app the
    customer created by hand in their own tenant (tenant ID, application ID, client secret
    or certificate). A token for exactly that tenant is the proof; the credential is sealed in the
    organisation's secret store and never shown again, and entering new values replaces it.
    The worker, the group picker of the directory and the permission check use the source's
    own app. Sources with their own app have no consent link. The connection card names the
    organisation the source belongs to before anything is connected.
    See docs/ENTRA-SETUP.md ("Alternative: eine eigene App pro Quelle").
  • The tenant the backup app lives in connects without a consent link. "Connect own
    tenant directly" on the source page (provider owners only) uses a working app token
    for the home tenant as proof, so the consent round trip, which failed with
    AADSTS700016 there, is skipped. It needs the directory (tenant) ID (a GUID) of the app
    under Settings, Microsoft 365.

Updates

  • Alpha channel for test builds. Builds of the alpha/* branches
    (.github/workflows/alpha.yml) push unsigned images to
    ghcr.io/restow-backup/restow-alpha and announce themselves as pre-releases of the alpha
    repository. On Installation, Updates, "Use the alpha channel" selects that source in one
    click. The tab warns while the alpha source is selected and while the updater does not
    verify signatures (the updater now reports this as signatureChecks).

Changed

  • The Installation section of the menu is pinned to the bottom, set apart and labelled as
    applying to every organisation of the installation, so installation-wide settings are
    told apart from those of the active organisation.
  • The Hetzner Object Storage preset has a location selector (Falkenstein, Nuremberg,
    Helsinki) that sets endpoint and region together.

Fixed

  • A source for the tenant of the backup app could not be connected: the page only knew the
    consent link, which Entra refuses for an app that is not installed in that tenant (AADSTS700016).
  • A bucket with a dot in its name could not be reached with the Hetzner preset, because the
    provider's wildcard certificate does not cover the extra label; such buckets are now always
    addressed by path.
  • A bucket created with Object Lock was shown as "not active": S3-compatible services such as
    Hetzner answer in another case or send only the default rule, which the detection did not
    accept.

Security

  • The dependency audit failed on new advisories in the test tooling (tinypool below
    2.1.2 and source-map-js below 1.2.2, both reached only through vitest). Neither is part
    of a shipped image; both are overridden to the patched versions.
  • The images apply the Debian security updates of the base image when they are built. The
    release smoke refused the first 0.2.2 build because the base image still carried
    perl-base 5.36.0-7+deb12u3, which has three critical vulnerabilities fixed in
    5.36.0-7+deb12u4. No release image ever contained the unpatched package.
  • Connecting the tenant of the backup app without consent is restricted to provider owners,
    to the home tenant set by the provider (a GUID), and to a source that is not connected yet, so
    no organisation can bind a foreign tenant this way.
  • The credentials of a source's own Graph app are sealed with the organisation's key, are never
    returned by the API and are not written to the audit log.

Upgrade Notes

Kind of update: new image, no manual steps. Follow Updating: in the
updater tab, or docker compose pull && docker compose up -d.

  • Database migrations: none.
  • New or changed environment variables: none. To test alpha builds, set
    RESTOW_UPDATER_IMAGE_REPOSITORY, RESTOW_UPDATER_WEB_IMAGE_REPOSITORY and
    RESTOW_UPDATER_VERIFY_SIGNATURES=false once on a test installation (docs/UPDATING.md,
    "Alpha builds"). Do not do this on an installation with production data.
  • Expected downtime: the containers restart once.
  • Rollback: the previous tag plus docker compose up -d; no migration ran, so no database
    restore is needed.

Known Issues

  • Connecting through a Graph app of your own and connecting the home tenant directly were
    tested with unit tests and the CI suites only, not against a real Microsoft 365 tenant. The
    Postgres-backed paths of the new routes have no tests of their own yet.
  • The Hetzner preset and the Object Lock detection were not tested against a real Hetzner bucket.
  • A source connected by consent cannot be switched to a Graph app of its own in the interface.
  • The alpha channel needs a repository secret (ALPHA_RELEASE_TOKEN) and a first commit in the
    alpha repository before builds are announced to the updater.
  • A tag signature is reported by the release workflow but not required for this release.

Verification

Verified by the continuous integration of the release commit: lint, type check, build of all
packages and of the web bundle, unit and Postgres test suites, installer tests, dependency
audit and licenses, secret scan, workflow lint, the Go agent, and the build of the full and
Community images.

Run locally before the release: unit tests of core (1930 tests), api (2150), worker (248) and
web (the storage, sources, updates and layout suites, all passing).

Not run: any check against a real Microsoft 365 or Hetzner account. The release smoke checks
of the pipeline are added below by the release workflow.

Release pipeline, 2026-10-06:

Check Result Duration
1. Install: images, compose up, migrations (new install and upgrade) PASS 80s
2. Health endpoints, worker and scheduler registered PASS 0s
3. Passkey sign-in E2E with a virtual authenticator, tenant creation, i18n de/en PASS 115s
4. Microsoft 365 backup and restore against the dev tenant SKIPPED 0s
5. IMAP backup and restore against Dovecot, hash comparison PASS 8s
6. Journal receipt, chain verification, export PASS 3s
7. Standalone restore with restow-restore from the storage of check 5 PASS 24s
8. Storage targets: S3 (Garage), local path, mounted directory PASS 21s
9. Image scan (Trivy) and dependency audit (pnpm audit) PASS 20s
10. Endpoint backup: the agent enrolls, backs up a folder, restores it PASS 11s
11. Mail import (folder and upload) and export (EML ZIP, MBOX), compared by hash PASS 9s

10 of 11 checks passed in full, 0 partly, 1 skipped, 0 failed. The full report, including the reason for every skipped or partial check, is attached to the release as smoke-report.md.

The Community images were smoke-tested on their own (smoke-report-community.md, smoke-report-community-arm64.md): amd64 PASS with gaps: 8 of 11 checks passed in full, 0 partly, 3 skipped (see the reasons below); arm64 PASS with gaps: 8 of 11 checks passed in full, 0 partly, 3 skipped (see the reasons below).

Images

Two builds of the same release. The full build is the Apache-2.0 core plus the Business and Service Provider modules (Restow Enterprise License), which stay locked until a license key is installed. The Community build is the Apache-2.0 core alone.

ghcr.io/restow-backup/restow:0.2.2
ghcr.io/restow-backup/restow-web:0.2.2
ghcr.io/restow-backup/restow-community:0.2.2
ghcr.io/restow-backup/restow-web-community:0.2.2

The digests of the multi-arch manifests (the opt-in updater verifies the pulled images against the two lines of its build):

restow: sha256:aea6a0d224781a384bbfb3589878b3771171084abd55ea6b50d903afc0ecf7d7
restow-web: sha256:b199442ee6248605cc2719dc4850faab224993272cb1f6b56dff869e489a2287
restow-community: sha256:2b2b40662158c708363f2428b4c04cc39802c1b4c0965541b1726fd593429717
restow-web-community: sha256:5a056560a9610b88e845769fb7aaf4e0ab36b642fd41a9abe9c93f003877fad1

All four images are multi-arch (linux/amd64, linux/arm64), signed with cosign (keyless) and carry an SPDX SBOM as attestation. Verify any of them with:

cosign verify ghcr.io/restow-backup/restow:0.2.2 \
  --certificate-identity-regexp '^https://github.com/restow-backup/restow/\.github/workflows/release\.yml@refs/tags/v' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/restow-backup/restow-web:0.2.2 \
  --certificate-identity-regexp '^https://github.com/restow-backup/restow/\.github/workflows/release\.yml@refs/tags/v' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/restow-backup/restow-community:0.2.2 \
  --certificate-identity-regexp '^https://github.com/restow-backup/restow/\.github/workflows/release\.yml@refs/tags/v' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/restow-backup/restow-web-community:0.2.2 \
  --certificate-identity-regexp '^https://github.com/restow-backup/restow/\.github/workflows/release\.yml@refs/tags/v' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

docker-compose.yml and env.example are the release stack (deploy/release/); install.sh installs it on a dedicated Linux VM (README.md, "Install with the script"; install.sh.sha256 for sha256sum -c after the download); restow-agent-THIRD_PARTY_NOTICES.txt holds the licenses of the agent binaries and of the restic they run; SHA256SUMS lists every file of this release and is signed (SHA256SUMS.sigstore.json).