diff --git a/.github/workflows/sync-upstream.yml b/.github/workflows/sync-upstream.yml new file mode 100644 index 0000000000..49bf5da928 --- /dev/null +++ b/.github/workflows/sync-upstream.yml @@ -0,0 +1,126 @@ +name: Sync upstream + +on: + schedule: + - cron: '23 6 * * *' + workflow_dispatch: + +# Pushes use an app installation token; the built-in token only handles the +# failure issue and the inactivity-timer reset. +permissions: + contents: read + issues: write + actions: write + +jobs: + sync: + runs-on: ubuntu-latest + steps: + # GitHub disables cron workflows in public repos after 60 days without + # repository activity, and this repo is only active when upstream + # releases. Re-enabling an enabled workflow resets that timer. + - name: Reset the scheduled-workflow inactivity timer + env: + GH_TOKEN: ${{ github.token }} + run: gh api -X PUT 'repos/${{ github.repository }}/actions/workflows/sync-upstream.yml/enable' + + - uses: actions/create-github-app-token@v3 + id: app-token + with: + client-id: ${{ secrets.FORK_SYNC_APP_CLIENT_ID }} + private-key: ${{ secrets.FORK_SYNC_APP_KEY }} + + - uses: actions/checkout@v7 + with: + ref: peerdb + fetch-depth: 0 + token: ${{ steps.app-token.outputs.token }} + + # The target tag is the upstream base's major.minor plus the number + # of extra commits in the fork. A release is due whenever that tag + # doesn't exist yet — a new upstream release, freshly merged fork PRs, + # or both. The upstream tag goes to FETCH_HEAD, never a local tag ref + # (the fork's own tag names live in the same vX.Y.Z namespace). + - name: Determine release + id: rel + run: | + git remote add upstream https://github.com/golang/crypto + latest=$(git ls-remote --tags upstream 'v*' | awk -F/ '{print $NF}' \ + | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1) + git fetch --no-tags upstream "refs/tags/$latest" + new_commit=$(git rev-parse 'FETCH_HEAD^{commit}') + base_commit=$(git merge-base HEAD "$new_commit") + n=$(git rev-list --count "$base_commit..HEAD") + target="${latest%.*}.$n" + if git ls-remote --exit-code origin "refs/tags/$target" >/dev/null; then + echo "Up to date: $target already released" + echo "target=" >> "$GITHUB_OUTPUT" + else + echo "Release due: $target (upstream $latest + $n fork commits)" + echo "target=$target" >> "$GITHUB_OUTPUT" + fi + echo "new_commit=$new_commit" >> "$GITHUB_OUTPUT" + echo "base_commit=$base_commit" >> "$GITHUB_OUTPUT" + + - name: Rebase fork commits onto new upstream base + if: steps.rel.outputs.target != '' && steps.rel.outputs.base_commit != steps.rel.outputs.new_commit + run: | + git config user.name 'peerdb-fork-sync[bot]' + git config user.email 'peerdb-fork-sync[bot]@users.noreply.github.com' + echo "Rebasing onto ${{ steps.rel.outputs.new_commit }}" + git rebase --onto '${{ steps.rel.outputs.new_commit }}' '${{ steps.rel.outputs.base_commit }}' peerdb + + - name: Determine PeerDB Go version + id: go + run: | + version=$(curl -fsSL https://raw.githubusercontent.com/PeerDB-io/peerdb/main/flow/go.mod | awk '/^go /{print $2}') + echo "PeerDB uses go $version" + echo "version=$version" >> "$GITHUB_OUTPUT" + + - uses: actions/setup-go@v7 + with: + go-version: ${{ steps.go.outputs.version }} + check-latest: true + cache: false + + # Only the root ssh package: ssh/test and ssh/agent replay recorded + # transcripts that hardcode upstream's 2 MiB window, so the patch + # invalidates them by design. The root package runs full in-memory + # handshakes against the patched code. + - name: Validate + run: | + go build ./... + go test ./ssh/ + + # master mirrors the upstream base of the current release, so + # master...peerdb always shows the full fork delta. + - name: Push branch, tag, and upstream-base master + if: steps.rel.outputs.target != '' + run: | + git push --force origin peerdb + git tag '${{ steps.rel.outputs.target }}' peerdb + git push origin 'refs/tags/${{ steps.rel.outputs.target }}' + git push origin '${{ steps.rel.outputs.new_commit }}':refs/heads/master + + # Each failing run opens its own issue; a green run closes every open + # sync-failure issue. Alerting subscribes to issue open/close events, + # so each failure and each recovery notifies exactly once. + - name: Open failure issue + if: failure() + env: + GH_TOKEN: ${{ github.token }} + run: | + run_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + gh label create sync-failure -R "${{ github.repository }}" --force --description 'Upstream sync is broken' + body="The upstream sync workflow failed: $run_url"$'\n\n'"Likely a rebase conflict with a new upstream release, or an ssh test failure. See README's Maintenance section. Each failing run opens a new issue; the next green run closes all open ones." + gh issue create -R "${{ github.repository }}" --title "Upstream sync failing ($(date -u +%Y-%m-%d))" --label sync-failure --body "$body" + + - name: Close failure issues on recovery + if: success() + env: + GH_TOKEN: ${{ github.token }} + run: | + gh issue list -R "${{ github.repository }}" --label sync-failure --state open --json number --jq '.[].number' \ + | while read -r n; do + gh issue close "$n" -R "${{ github.repository }}" --comment 'Sync succeeded; closing.' + done diff --git a/README.md b/README.md index f69c623ff8..e25f3c8bd0 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,74 @@ -# Go Cryptography +# PeerDB fork of golang.org/x/crypto -[![Go Reference](https://pkg.go.dev/badge/golang.org/x/crypto.svg)](https://pkg.go.dev/golang.org/x/crypto) +PeerDB's fork of [golang/crypto](https://github.com/golang/crypto). It +carries one patch: the SSH channel receive window in the `ssh` package is +raised from upstream's hardcoded 2 MiB to 8 MiB (`channelWindowSize` in +`ssh/channel.go`). PeerDB moves bulk CDC (change data capture) traffic +through SSH tunnels, and SSH throughput caps at window ÷ round-trip time, so +on high-bandwidth, high-latency links the 2 MiB window holds throughput +below link capacity. -This repository holds supplementary Go cryptography packages. +## Layout -## Report Issues / Send Patches +| Ref | Contents | How it changes | +|---|---|---| +| `peerdb` (default branch) | Latest upstream release tag + the fork's commits: the patch, this README, the sync workflow | Sync workflow rebases and force-pushes it on each upstream release; manual changes via pull request | +| `master` | The upstream base of the current release, unpatched | Fast-forwarded by the sync workflow | +| `vX.Y.N` tags | Upstream tag `vX.Y.0` + the fork's N commits | Cut by the sync workflow on upstream releases; by hand for releases in between | -This repository uses Gerrit for code changes. To learn how to submit changes to -this repository, see https://go.dev/doc/contribute. +The patch version is the number of extra commits in the fork. Upstream only +ever tags `vX.Y.0` and the fork always has at least one extra commit, so +every fork tag +gets a fresh name and a published tag is never moved or recreated — which is +what the Go module proxy requires: it pins tag→hash on the first fetch. +(`v0.55.0` predates this scheme.) The full fork delta is +[`master...peerdb`](https://github.com/PeerDB-io/crypto/compare/master...peerdb). -The git repository is https://go.googlesource.com/crypto. +## Staying current with upstream -The main issue tracker for the crypto repository is located at -https://go.dev/issues. Prefix your issue with "x/crypto:" in the -subject line, so it is easy to find. +`.github/workflows/sync-upstream.yml` runs daily (and on manual dispatch): -Note that contributions to the cryptography package receive additional scrutiny -due to their sensitive nature. Patches may take longer than normal to receive -feedback. +1. Computes the target tag: the latest upstream release's `vX.Y` plus the + number of extra commits in the fork. A release is due whenever that tag + doesn't exist yet — a new upstream release, freshly merged fork PRs, or + both. +2. Rebases the fork's commits onto the upstream tag when the base moved. +3. Builds all packages and tests the root `ssh` package, using the Go + version from PeerDB's `flow/go.mod`. +4. Force-pushes `peerdb` and pushes the target tag. + +Each failing run opens a fresh `sync-failure` issue; the next green run +closes all open ones. + +Validation covers the root `ssh` package, which runs full in-memory +handshakes against the patched code. The `ssh/test` and `ssh/agent` +packages replay recorded transcripts that embed upstream's 2 MiB window, so +they fail against this patch and are excluded. + +## How PeerDB consumes it + +`flow/go.mod` in [PeerDB](https://github.com/PeerDB-io/peerdb) keeps +`require golang.org/x/crypto` and adds +`replace golang.org/x/crypto => github.com/PeerDB-io/crypto`. Renovate in +that repo follows this repo's tags and opens the bump PRs. + +## Maintenance + +- **Sync failure**: each open `sync-failure` issue links its failed run. + Typical causes: a rebase conflict with a new upstream release, or an + `ssh` test failure. Adjust the fork's commits on `peerdb` via PR until + they apply cleanly, then re-run the workflow. +- **Changing the patch**: PR against `peerdb`, then re-run the workflow + (manual dispatch) to cut the tag. +- Keep the delta minimal. + +## Scope + +This fork exists for PeerDB. Other projects should depend on +`golang.org/x/crypto`, and `ssh` package issues belong +[upstream](https://go.dev/issues). Issues in this repo cover the fork's +automation only. + +## License + +Upstream's BSD-style license applies; see `LICENSE`. diff --git a/ssh/channel.go b/ssh/channel.go index ba3279e91d..aa98947062 100644 --- a/ssh/channel.go +++ b/ssh/channel.go @@ -20,8 +20,10 @@ const ( // sent in a single packet. As per RFC 4253, section 6.1, 32k is also // the minimum. channelMaxPacket = 1 << 15 - // We follow OpenSSH here. - channelWindowSize = 64 * channelMaxPacket + // Upstream uses 64 packets (2 MiB), following OpenSSH. The larger + // receive window avoids throttling bulk CDC traffic on high-bandwidth, + // high-latency SSH links. + channelWindowSize = 256 * channelMaxPacket ) // NewChannel represents an incoming request to a channel. It must either be