diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..4230f60 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,19 @@ +## Summary + + + +## Changes + + + +## 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 + + diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..47ffec1 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -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 }}" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..86bee18 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -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 diff --git a/.trivyignore b/.trivyignore index 7519859..d6fff8a 100644 --- a/.trivyignore +++ b/.trivyignore @@ -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 diff --git a/docker/Dockerfile b/docker/Dockerfile index 9ab5431..2dfb90a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -32,10 +32,10 @@ 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 @@ -43,8 +43,8 @@ ARG SUPERCRONIC_VERSION=0.2.46 # 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 @@ -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 diff --git a/docs/ToDo.md b/docs/ToDo.md new file mode 100644 index 0000000..6f9e9da --- /dev/null +++ b/docs/ToDo.md @@ -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=(?[^\\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).