Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Summary

<!-- What does this PR do and why? One or two sentences. -->

## Changes

<!-- Bullet list of the meaningful changes. Delete this section for trivial fixes. -->

## Test plan

- [ ] CI passes (ShellCheck, bats, Hadolint, Trivy, gitleaks)
- [ ] Tested locally with `./run-backup.sh --dry-run`
- [ ] For new scripts: added or updated tests in `tests/`
- [ ] For new env vars: documented in `config/.env.example`
- [ ] For version bumps: `CHANGELOG.md` updated and `synology/INFO` bumped if needed

## Notes for reviewer

<!-- Anything non-obvious about the approach, trade-offs accepted, or follow-up work. Delete if nothing to add. -->
40 changes: 40 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: CodeQL

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
# Weekly scan on Monday at 03:00 UTC, independent of PR activity.
- cron: "0 3 * * 1"

jobs:
analyze:
name: CodeQL analysis (${{ matrix.language }})
runs-on: ubuntu-latest
permissions:
security-events: write
actions: read
contents: read

strategy:
fail-fast: false
matrix:
language: [python]
# bash/shell is not a CodeQL-supported language; ShellCheck covers it.

steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Initialize CodeQL
uses: github/codeql-action/init@c20e34f438d671fc35777cc9820dd7adf8252874 # v3.38.0
with:
languages: ${{ matrix.language }}
queries: security-extended

- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@c20e34f438d671fc35777cc9820dd7adf8252874 # v3.38.0
with:
category: "/language:${{ matrix.language }}"
26 changes: 26 additions & 0 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Dependency review

on:
pull_request:
branches: [main]

jobs:
dependency-review:
name: Dependency review
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write

steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Dependency review
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
with:
# Fail the check if any dependency change introduces a vulnerability
# with a CVSS score >= 7 (HIGH or CRITICAL).
fail-on-severity: high
# Post a summary comment on the PR listing any new vulnerable deps.
comment-summary-in-pr: always
76 changes: 76 additions & 0 deletions .trivyignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,79 @@ CVE-2026-27145
# Sigstore transparency-log client bundled inside the gh CLI binary. GitPreserver
# does not use gh for signature verification; the rekor client is never invoked.
CVE-2026-48702
# ---------------------------------------------------------------------------
# Go module CVEs in upstream-prebuilt binaries (ghorg, rclone) — 2026-09-09 scan
# ---------------------------------------------------------------------------
# rclone 1.74.4 fixes CVE-2026-54572 (symlink arbitrary write) — Dockerfile
# upgraded. The remaining findings below are transitive Go module CVEs inside
# the ghorg and rclone binaries with no new upstream release yet.
# Accepted by @dougeubanks on 2026-09-09.
#
# golang.org/x/crypto/ssh (ghorg, rclone): CRITICAL SSH DoS — ghorg uses SSH
# for git clone/fetch against our own repos; rclone uses it for SFTP remotes.
# Neither acts as an SSH server accepting untrusted inbound connections.
CVE-2026-56854
# golang.org/x/net (ghorg, rclone): DNS message and HTML parsing issues.
CVE-2026-46600
# golang.org/x/text (ghorg, rclone): DoS via malformed Unicode input.
CVE-2026-56852
# golang.org/x/mod (ghorg): Malicious GOSUMDB could serve arbitrary module zip.
# Requires the operator to have pointed GOSUMDB at an attacker-controlled server.
CVE-2026-56864
# google.golang.org/grpc (ghorg, rclone): gRPC vulnerability in bundled library.
# GitPreserver does not expose any gRPC endpoints or connect to untrusted gRPC servers.
CVE-2026-84304
# Go stdlib encoding/asn1 (ghorg, rclone): DoS in ASN.1 parsing.
CVE-2026-33818
# golang.org/x/image (rclone): TIFF decoder size limit absent — only reachable
# if rclone is syncing a maliciously crafted TIFF; not a network-facing issue
# for a git-backup tool reading our own repos.
CVE-2026-46602
# ---------------------------------------------------------------------------
# Go module CVEs in upstream-prebuilt binaries (ghorg, rclone) — 2026-09-09 scan (2nd pass)
# ---------------------------------------------------------------------------
# rclone 1.75.0 fixes CVE-2026-71309 (backend root escape) — Dockerfile upgraded.
# The findings below are transitive Go module CVEs with no upstream release yet.
# Accepted by @dougeubanks on 2026-09-09.
#
# golang.org/x/crypto (ghorg): additional SSH CVEs beyond those suppressed above.
CVE-2026-39831
# golang.org/x/image (rclone): vp8l decoder DoS — rclone image processing, not
# directly invoked by GitPreserver's sync workflow.
CVE-2026-46603
# golang.org/x/mod (ghorg): sumdb/tlog vulnerability — requires a malicious
# GOSUMDB, not a realistic attack vector in this deployment.
CVE-2026-56865
# google.golang.org/grpc (ghorg, rclone): xDS server DoS — neither binary runs
# an xDS server; the affected codepath is not reachable.
CVE-2026-84445
# Go stdlib os.Root (ghorg): symlink following in os.Root API — ghorg uses
# standard filesystem ops; the os.Root API is not called directly by GitPreserver.
CVE-2026-39822
# Go stdlib net/http (rclone): unencrypted HTTP/2 — rclone communicates with
# configured remotes over HTTPS; this path requires a downgrade attack.
CVE-2026-56853
# Go stdlib html/template (ghorg): XSS via crafted HTML template data — ghorg
# does not render HTML templates from user input; not reachable in a git-cloning
# workflow.
CVE-2026-56858
# ---------------------------------------------------------------------------
# Go module CVEs in upstream-prebuilt binaries (ghorg, rclone) — 2026-09-09 scan (3rd pass)
# ---------------------------------------------------------------------------
# New Go stdlib and grpc findings from the same binaries, no upstream release yet.
# Accepted by @dougeubanks on 2026-09-09.
#
# google.golang.org/grpc (ghorg, rclone): xDS RBAC and HTTP/2 vulnerabilities,
# fixed in grpc 1.82.1. GitPreserver does not expose any gRPC endpoints or
# connect to untrusted gRPC servers; neither the xDS nor RBAC paths are invoked.
GHSA-hrxh-6v49-42gf
# Go stdlib encoding/xml (ghorg, rclone): DoS via XML recursion depth — ghorg
# and rclone do not parse untrusted XML input in a git-backup workflow.
CVE-2026-56859
# Go stdlib net/url (ghorg, rclone): DoS via malformed URL — URLs processed
# by these binaries come from our own configuration, not untrusted user input.
CVE-2026-56860
# Go stdlib crypto/tls (ghorg, rclone): DoS via crafted TLS — these binaries
# connect as TLS clients to known remotes; they do not accept untrusted inbound
# TLS connections.
CVE-2026-56862
10 changes: 5 additions & 5 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@ FROM debian:bookworm-slim AS builder
# pipefail catches mid-pipeline failures in `curl | tar` style installs below.
SHELL ["/bin/bash", "-o", "pipefail", "-c"]

# Pinned tool versions (latest stable as of 2026-06-12).
# Pinned tool versions (rclone bumped to 1.75.0 on 2026-09-09 for CVE-2026-71309).
ARG GHORG_VERSION=1.11.11
ARG GH_VERSION=2.94.0
ARG RCLONE_VERSION=1.74.3
ARG RCLONE_VERSION=1.75.0
ARG SUPERCRONIC_VERSION=0.2.46

# SHA256 checksums per architecture, from upstream release checksum files
# (supercronic hashes computed from the released binaries — it ships none).
# Refresh these whenever a version ARG above changes.
ARG SUPERCRONIC_SHA256_AMD64=5adff01c5a797663948e656d2b61d10932369ee437eb5cb54fa872b2960f222b
ARG SUPERCRONIC_SHA256_ARM64=c0576a8eb092e3f79108ed0a2155a25c7766af78456e5a6070e54757ef513bfe
ARG RCLONE_SHA256_AMD64=dbee7ccd7a5d617e4ed4cd4555c16669b511abfe8d31164f61be35ac9e999bd2
ARG RCLONE_SHA256_ARM64=8f8d47446e061f80c3256659fe8e21f56d72d96aaefe1275d088ea5eb6b42aa7
ARG RCLONE_SHA256_AMD64=aa2804e08f48250e71009c727124b6341cd0288465804a9a09d14663cabafbaa
ARG RCLONE_SHA256_ARM64=d0ad88ba4c8e285b7c9efa591e0ab643280a91741e13c27f3a9c0957ccfa5203
ARG GH_SHA256_AMD64=a757f1ba6db18f4de8cbadb244843a5f89bc75b5e7c6fc127d2bd77fbd12ed62
ARG GH_SHA256_ARM64=705a23b70b0f1b7ba4c302fdcef392ce3edaacfa7ce8e85e4d93d72ea800a538
ARG GHORG_SHA256_AMD64=3f479d2e6d376114ddb0a24af4774d2f28eb6a735f5d9f3a2d1847df61d85752
Expand Down Expand Up @@ -132,7 +132,7 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Keep in sync with the builder-stage version ARGs above.
ARG GHORG_VERSION=1.11.11
ARG GH_VERSION=2.94.0
ARG RCLONE_VERSION=1.74.3
ARG RCLONE_VERSION=1.75.0
ARG SUPERCRONIC_VERSION=0.2.46
ARG PUID=1000
ARG PGID=1000
Expand Down
35 changes: 35 additions & 0 deletions docs/ToDo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# GitPreserver — To Do

Tracked improvements that are not yet scheduled for a specific release.
Move items to the relevant `[Unreleased]` CHANGELOG section when work begins.

---

## Security

### Automate binary version tracking with Renovate regex managers

**Priority:** High
**Context:** The four tool binaries bundled in `docker/Dockerfile` — `ghorg`, `gh`, `rclone`, and `supercronic` — are downloaded via `curl` and pinned by version ARG. Dependabot cannot discover or bump curl-fetched assets, so CVEs in these binaries are only caught by Trivy and require manual version bumps and SHA256 updates.

**What to do:**
Adopt [Renovate](https://docs.renovatebot.com/) alongside or instead of Dependabot and add `regexManagers` rules that match the `ARG *_VERSION=` lines in the Dockerfile. Renovate's regex manager can track GitHub releases for each tool and open PRs that update both the version ARG and the corresponding SHA256 ARG in one commit.

Example manager shape (one per tool):
```json
{
"regexManagers": [
{
"fileMatch": ["docker/Dockerfile"],
"matchStrings": ["ARG RCLONE_VERSION=(?<currentValue>[^\\n]+)"],
"depNameTemplate": "rclone/rclone",
"datasourceTemplate": "github-releases"
}
]
}
```

The SHA256 ARGs would still need to be refreshed manually or via a companion script unless Renovate's `postUpgradeTasks` feature is used to run a checksum-fetch script as part of the PR.

**Workaround until done:**
Run `docker/Dockerfile` binary versions through Trivy on every PR (already in CI). When Trivy flags a CVE with an available fix in one of these binaries, bump the version ARG and SHA256 ARGs manually as done for rclone 1.74.3 → 1.74.4 (CVE-2026-54572, 2026-09-09).
Loading