Skip to content

Conversation

@kraftbj
Copy link
Contributor

@kraftbj kraftbj commented Jan 28, 2026

Proposed changes:

  • Split rsync execution so Docker collects files (filter rules + metadata) and the host runs rsync with native SSH. This enables support for Secure Enclave SSH keys (e.g. AutoProxxy) that cannot be forwarded into Docker containers.
  • Add --prepare-filters mode to rsync.js inside Docker: collects paths, writes filter rules and metadata to tools/docker/data/rsync/, and touches a trigger file for the host to detect.
  • Host-side jp.js detects when rsync is invoked (without --config, --help, or -h) and handles the split: runs Docker for file collection, then executes rsync natively on the host.
  • In watch mode, Docker spawns with --prepare-filters and the host polls a trigger file, running rsync each time Docker signals a change.
  • Fix watch mode output interleaving: capture rsync output and use \r\n line endings since Docker exec leaves the host terminal in raw mode.
  • Pass --help and -h flags through to Docker directly instead of entering split mode.

Other information:

  • Have you written new tests for your changes, if applicable?
  • Have you checked the E2E test CI results, and verified that your changes do not break them?
  • Have you tested your changes on WordPress.com, if applicable (if so, you'll see a generated comment below with a script to run)?

Jetpack product discussion

N/A — this is a developer tooling change to the Jetpack CLI (jp rsync), not a product change.

Does this pull request change what data or activity we track or use?

No. This change only affects local developer tooling (the jp rsync command). No tracking or data collection is added or modified.

Testing instructions:

Setup

  1. Link the development version of the Jetpack CLI globally:
    cd projects/js-packages/jetpack-cli
    npm link
  2. Verify the dev version is active:
    which jp
    # Should point to your nvm node_modules
    npm list -g @automattic/jetpack-cli

Test: --help flag

  1. Run jp rsync --help
  2. Verify it shows the help text cleanly without errors (previously showed "rsync metadata not found" error).

Test: Single rsync

  1. Run jp rsync and select a plugin and destination.
  2. Verify files sync correctly to the remote destination.
  3. Verify the AUTOLOAD_DEV warning banner displays correctly.

Test: Watch mode

  1. Run jp rsync --watch and select a plugin and destination.
  2. Verify the initial sync completes and the AUTOLOAD_DEV warning banner displays with clean formatting (no staircase/offset lines).
  3. Make a file change in the selected plugin directory.
  4. Verify the watcher detects the change and re-syncs, with clean output.
  5. Press Ctrl+C to stop — verify it exits cleanly.

Test: SSH agent forwarding (if applicable)

  1. If you have a Secure Enclave SSH key (e.g. AutoProxxy), verify that jp rsync works with remote destinations that require it.
  2. This was previously broken because Docker cannot access Secure Enclave keys.

Cleanup

When done testing, restore the published version of the CLI:

npm unlink -g @automattic/jetpack-cli
npm install -g @automattic/jetpack-cli

Docker cannot access macOS Secure Enclave SSH keys (AutoProxxy), so
rsync needs to run on the host with native SSH. This adds a two-phase
mode: Docker handles file collection, prompts, and watch/debounce via
a new --prepare-filters flag, writing filter rules and metadata to
tools/docker/data/rsync/. The host-side jp.js watches for trigger
file changes and runs rsync natively.

--config continues to run entirely in Docker (no SSH needed).
Copilot AI review requested due to automatic review settings January 28, 2026 17:44
@kraftbj kraftbj self-assigned this Jan 28, 2026
@github-actions github-actions bot added [JS Package] Jetpack CLI [Tools] Development CLI The tools/cli to assist during JP development. RNA labels Jan 28, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Jan 28, 2026

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a split-execution model for rsync to enable SSH agent forwarding support with Secure Enclave keys. The change addresses a limitation where Docker containers cannot access Secure Enclave SSH keys (e.g., AutoProxxy), by having Docker handle file collection and the host system execute rsync with native SSH.

Changes:

  • Introduced --prepare-filters mode in rsync.js where Docker collects files, generates filter rules, and writes metadata for host-side execution
  • Added split-mode handling in jp.js that detects rsync invocations and orchestrates the Docker-for-collection + host-for-rsync workflow
  • Fixed watch mode output formatting issues by using \r\n line endings and capturing rsync output to handle terminal raw mode

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.

File Description
tools/cli/commands/rsync.js Added --prepare-filters flag, writeFilterFile() and prepareFiltersAndSignal() functions to support split execution; updated watch mode to conditionally use prepare-filters workflow
projects/js-packages/jetpack-cli/bin/jp.js Implemented handleRsyncSplit(), runHostRsync(), detectOpenrsync(), and helper functions to orchestrate split execution on the host side; added rsync command interception in main execution flow
projects/js-packages/jetpack-cli/changelog/add-monorepo-ssh-agent-forwarding Added changelog entry documenting the feature change

@kraftbj kraftbj added [Status] Needs Review This PR is ready for review. and removed [Status] In Progress labels Jan 28, 2026
@kraftbj kraftbj requested a review from a team January 28, 2026 18:06
@anomiex
Copy link
Contributor

anomiex commented Jan 28, 2026

Maybe this is the way we'll have to go, but the amount of code copy-pasted from tools/cli into jp isn't great and having to have jp account for openrsync is even less great.

What might work better would be to use --rsh to use a custom command that will have the host ssh to the destination while rsync runs inside the container. I have a proof of concept working locally in Linux (hopefully the idea works on Mac too); the general idea would be to do like this:

  • Update the Dockerfile to install socat inside the container along with everything else.
  • Inside the container there should exist a script something like this:
    #!/bin/bash
    
    printf '#!/bin/bash\n\nssh' > /tmp/rsync-dir/cmd.sh
    printf ' %q' "$@" >> /tmp/rsync-dir/cmd.sh
    chmod +x /tmp/rsync-dir/cmd.sh
    exec socat - UNIX-LISTEN:/tmp/rsync-dir/stdio.sock,mode=0777
  • Update tools/docker/bin/monorepo to also pass -v "$RSYNCDIR:/tmp/rsync-dir" if environment variable $RSYNCDIR is set.
  • jp rsync would then do something like this:
    • Create a temporary directory.
    • Run a background process that does the following:
      • Wait for a file stdio.sock to appear in the temporary directory.
      • Connect to that stdio.sock (it's a unix domain socket).
      • There will also be cmd.sh in the temporary directory. Execute that with its stdin and stdout connected to the socket.
    • Run tools/docker/bin/monorepo pnpm jetpack rsync ..., with environment variable RSYNCDIR set to point to the temporary directory. Somehow have jetpack rsync pass --rsh path/to/above-script.sh to rsync.
      • rsync will run the above script, which will write the necessary ssh command into cmd.sh and then create and listen on stdio.sock. The background process, which is running on the host, will run the ssh command and proxy the output back into Docker via the socket.
    • Kill the background process (if it's still running) and clean up the temporary directory on exit, even if jp is aborted with Ctrl+C or the like.

@kraftbj kraftbj added [Status] In Progress and removed [Status] Needs Review This PR is ready for review. labels Jan 30, 2026
@kraftbj
Copy link
Contributor Author

kraftbj commented Jan 30, 2026

@anomiex I think I have something working along your idea in #46867

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants