fix: disable VS Code exec-server mode incompatible with ProxyCommand SSH#403
fix: disable VS Code exec-server mode incompatible with ProxyCommand SSH#403skevetter wants to merge 9 commits into
Conversation
The semantic-release workflow uses actions/setup-node with npm caching, which requires a lock file to be present. Also switches from npm install to npm ci for reproducible CI builds.
…cted branch The @semantic-release/git plugin attempts to push CHANGELOG.md commits directly to the protected main branch, which fails due to branch protection rules (verified signatures, PR requirement, status checks). Remove the plugin and @semantic-release/changelog since the changelog can't be committed without git push access. The @semantic-release/github plugin still creates GitHub releases with full release notes.
…plugins The v1.4.0-rc.1 tag left over from release-please caused semantic-release to fail with "tag already exists". Deleted the conflicting tag and added @semantic-release/changelog and @semantic-release/git plugins so releases generate a CHANGELOG.md and commit it back. Also pass GH_TOKEN env var for branch protection bypass.
…ature-protected branch Branch protection on main requires verified signatures. The @semantic-release/git plugin uses git push which does not produce GPG-signed commits even with App token + bot identity. Remove it and @semantic-release/changelog — release notes are delivered via GitHub Releases (@semantic-release/github) which uses the API and works correctly with branch protection.
# [1.4.0-rc.1](v1.3.0...v1.4.0-rc.1) (2026-05-19) ### Bug Fixes * **ci:** add package-lock.json for semantic-release workflow ([bcd9208](bcd9208)) * **ci:** add signed commit config and create-release-pr workflow ([c89325a](c89325a)) * **ci:** advance prerelease manifest past stable release ([#372](#372)) ([33a9d44](33a9d44)) * **ci:** pass app token via token input for softprops/action-gh-release ([#361](#361)) ([77a9373](77a9373)), closes [softprops/action-#release](https://github.com/softprops/action-/issues/release) * **ci:** re-add changelog and git plugins with signed commit support ([#375](#375)) ([ad6e3f9](ad6e3f9)) * **ci:** remove @semantic-release/git plugin that can't push to protected branch ([c3bf35c](c3bf35c)) * **ci:** remove @semantic-release/git plugin that cannot push to signature-protected branch ([e971f37](e971f37)) * **ci:** resolve semantic-release tag conflict and add changelog+git plugins ([d80ae42](d80ae42)) * update workspace_result.json paths on workspace rename ([#369](#369)) ([f06f4ba](f06f4ba)) ### Features * auto-overwrite stale agent binary and workspace clean command ([#364](#364)) ([76841a4](76841a4)) * **ci:** enable autoMergeRequest in release-please action ([#363](#363)) ([2f889bb](2f889bb)) * **ci:** migrate from release-please to semantic-release ([#374](#374)) ([9fcceef](9fcceef)) * **ci:** replace single release-please config with dual prerelease/stable setup ([#368](#368)) ([d985356](d985356))
…-release Per semantic-release FAQ, making commits during release adds significant complexity including branch protection bypass. Use GitHub Releases for changelog instead of committing CHANGELOG.md.
✅ Deploy Preview for devsydev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
📝 WalkthroughWalkthroughThis PR updates the release infrastructure by introducing a manual workflow to create release PRs, simplifying semantic-release configuration to remove automatic changelog and git plugins, switching to GitHub App token authentication, using deterministic dependency installation via ChangesRelease Infrastructure Modernization
Estimated Code Review Effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly Related PRs
Suggested Labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/create-release-pr.yml:
- Around line 15-24: Replace the mutable action tags with pinned full-length
commit SHAs and disable credential persistence: update the uses for
actions/create-github-app-token (id: app-token) and actions/checkout to
reference their specific commit SHAs instead of `@v3/`@v6, and add
persist-credentials: false to the actions/checkout step that currently uses
token: ${{ steps.app-token.outputs.token }} so the app token is not stored in
git config.
- Around line 26-46: Replace the unsafe inline interpolation of commit text into
the gh pr create --body flag with gh pr create --body-file to avoid shell
evaluation; in the "Create PR" step (env GH_TOKEN, using gh pr create) write the
contents of steps.commits.outputs.log to a securely created temporary file
(using a safe write like printf '%s' or redirect from the steps output) and pass
that filename to --body-file, ensure proper quoting when writing, and remove the
temp file after the command; keep the "Get commit log" step (id: commits) as-is
so you can reference steps.commits.outputs.log for the file contents.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 00008c52-074b-4268-83e2-f0cb530229cd
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (6)
.github/workflows/create-release-pr.yml.github/workflows/semantic-release.yml.gitignore.releaserc.jsonCHANGELOG.mdpackage.json
💤 Files with no reviewable changes (2)
- .gitignore
- package.json
| - uses: actions/create-github-app-token@v3 | ||
| id: app-token | ||
| with: | ||
| app-id: ${{ secrets.DEVSY_GITHUB_APP_ID }} | ||
| private-key: ${{ secrets.DEVSY_GITHUB_APP_PRIVATE_KEY }} | ||
|
|
||
| - uses: actions/checkout@v6 | ||
| with: | ||
| fetch-depth: 0 | ||
| token: ${{ steps.app-token.outputs.token }} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "create-release-pr.yml" -type fRepository: devsy-org/devsy
Length of output: 101
🏁 Script executed:
cat -n .github/workflows/create-release-pr.ymlRepository: devsy-org/devsy
Length of output: 1490
🌐 Web query:
GitHub Actions security best practices pinning commits SHAs vs version tags
💡 Result:
Best practice (for security): pin GitHub Actions to the full-length commit SHA of the action (not a version tag) when you want an immutable, deterministic dependency. Why SHAs are preferred over version tags 1) Tags are mutable pointers, while a full commit SHA is immutable. GitHub explicitly states that pinning an action to a full-length commit SHA is the only way to use an action as an immutable release, and it helps mitigate risk from a bad actor modifying the action’s repository. [1] 2) Even if you trust the action author, GitHub notes there is still risk with tag-based references because a tag can be moved or deleted if an attacker gains access. [1] 3) GitHub’s 2025 policy/enforcement feature reflects this security model: GitHub recommends pinning dependency versions to a specific commit SHA to prevent malicious code added to a new or updated branch/tag from being automatically used, and it can enforce workflows to fail unless actions are pinned to a full commit SHA. [2] When version tags are acceptable - GitHub’s documentation allows using tags for convenience, but explicitly frames it as less secure: “Pin actions to a tag only if you trust the creator.” [1] Operational guidance you should pair with SHA pinning - Verify the SHA belongs to the action’s repository (not a fork). GitHub recommends confirming that the selected SHA is from the action repository and not a repository fork. [1] - Keep pinned SHAs up to date using tooling such as Dependabot/Renovate (GitHub notes Dependabot creates alerts for actions pinned to SHAs). [1] - Consider organizational controls: GitHub supports configuring policies to require SHA pinning. [1][2] Practical takeaway for your workflows - Use: owner/repo@ for third-party actions you do not fully control. - Prefer version tags only when you explicitly accept the tradeoff (e.g., you trust the creator and understand that the tag can change).
Citations:
- 1: https://docs.github.com/en/actions/reference/security/secure-use
- 2: https://github.blog/changelog/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions/
🌐 Web query:
GitHub Actions persist-credentials false checkout security
💡 Result:
In GitHub Actions, the persist-credentials input for the actions/checkout action controls whether the repository's authentication token (typically GITHUB_TOKEN) is stored in the local Git configuration [1]. By default, this is set to true, which enables subsequent steps in the same job to execute authenticated Git commands like git push or git fetch automatically [1]. From a security perspective, setting persist-credentials to false is a recommended best practice to minimize the risk of credential exposure [2][3][4]. When set to true, any compromised action or malicious script running within the same job can read the stored token from the disk, potentially allowing an attacker to access or modify the repository [2][3]. Recent updates have improved how these credentials are handled: 1. Improved Security Mechanism: Instead of storing the token directly in the repository's.git/config file, newer versions of actions/checkout store credentials in a separate file within the $RUNNER_TEMP directory [5][1]. This change uses Git's includeIf mechanism to isolate the credentials, reducing the risk of accidental exposure [5]. 2. Hardening Workflows: Because the default behavior can still present a security risk if an action in the pipeline is compromised, many organizations now enforce persist-credentials: false across all their workflows [2][6]. If you disable persist-credentials (set it to false), you must manually configure credentials if your workflow requires authenticated Git operations [4]. For example, if you use an action that automatically commits changes (like a git-auto-commit action), you will need to re-authenticate or provide a token explicitly before that step runs [4]. To further secure your workflows, always consider the principle of least privilege, such as setting default GITHUB_TOKEN permissions to read-only at the repository or organization level [7]. Additionally, pin your actions to immutable commit SHAs rather than version tags to protect against supply chain attacks involving tag hijacking [8][9].
Citations:
- 1: https://github.com/actions/checkout
- 2: Remove
persist-credentialsor change the default tofalseactions/checkout#485 - 3: Remove
persist-credentialsor change the default tofalseactions/checkout#485 - 4: Reconfigure credentials when `persist-credentials: false` is set stefanzweifel/git-auto-commit-action#356
- 5: Persist creds to a separate file actions/checkout#2286
- 6: Always emit
persist-credentials: falsewith actions/checkout github/gh-aw#2641 - 7: https://www.aikido.dev/blog/checklist-github-actions
- 8: https://undercodenews.com/github-actions-nightmare-malicious-tag-hijack-sparks-massive-supply-chain-breach-shock/
- 9: https://gbhackers.com/compromised-github-action/
Pin workflow actions to commit SHAs and disable credential persistence.
Lines 15 and 21 use mutable version tags (@v3, @v6). Per GitHub security guidance, pin actions to full-length commit SHAs as the only way to ensure immutable, deterministic action versions and mitigate supply chain risks. Additionally, add persist-credentials: false to the checkout step to prevent the app token from being stored in the git config, reducing credential exposure risk if a subsequent action is compromised.
Suggested patch
- - uses: actions/create-github-app-token@v3
+ - uses: actions/create-github-app-token@<pinned-sha>
id: app-token
with:
app-id: ${{ secrets.DEVSY_GITHUB_APP_ID }}
private-key: ${{ secrets.DEVSY_GITHUB_APP_PRIVATE_KEY }}
- - uses: actions/checkout@v6
+ - uses: actions/checkout@<pinned-sha>
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
+ persist-credentials: false🧰 Tools
🪛 zizmor (1.25.2)
[warning] 21-24: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 15-15: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 21-21: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 15-15: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions
(github-app)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/create-release-pr.yml around lines 15 - 24, Replace the
mutable action tags with pinned full-length commit SHAs and disable credential
persistence: update the uses for actions/create-github-app-token (id: app-token)
and actions/checkout to reference their specific commit SHAs instead of `@v3/`@v6,
and add persist-credentials: false to the actions/checkout step that currently
uses token: ${{ steps.app-token.outputs.token }} so the app token is not stored
in git config.
| - name: Get commit log | ||
| id: commits | ||
| run: | | ||
| COMMITS=$(git log release..main --oneline) | ||
| { | ||
| echo "log<<EOF" | ||
| echo "$COMMITS" | ||
| echo "EOF" | ||
| } >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Create PR | ||
| env: | ||
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||
| run: | | ||
| gh pr create \ | ||
| --base release \ | ||
| --head main \ | ||
| --title "release: promote main to stable" \ | ||
| --body "## Commits being promoted | ||
|
|
||
| ${{ steps.commits.outputs.log }}" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/create-release-pr.yml | head -60Repository: devsy-org/devsy
Length of output: 1490
🌐 Web query:
gh pr create --body-file option documentation
💡 Result:
The --body-file flag for the GitHub CLI command gh pr create allows you to read the body text of a pull request from a specified file [1][2]. Usage: gh pr create --body-file Key details: - You can use "-" as the filename to read the body text from standard input (stdin) [1][2]. - This flag is particularly useful for creating pull requests with long or multi-line bodies, as it helps avoid issues with command-line length limits in certain environments (such as Windows) [3]. - It was introduced to facilitate the automation of pull request creation using shell scripts or other non-interactive contexts [3][4]. - If you need to use a pull request template as a starting point, you can use the --template flag instead [1][2], though the --body-file flag can be used to provide the full content directly [5]. This option is part of the standard GitHub CLI (gh) documentation [1][6].
Citations:
- 1: https://cli.github.com/manual/gh_pr_create
- 2: https://www.gsp.com/cgi-bin/man.cgi?section=1&topic=GH-PR-CREATE
- 3: Add
pr create --body-fileflag cli/cli#3018 - 4: gh pr create --body flag should accept file reading or template edition cli/cli#2914
- 5: Allow "gh pr create" to specify a pull request template to use cli/cli#2567
- 6: https://man.archlinux.org/man/gh-pr-create.1.en
🏁 Script executed:
cd /tmp && git init test-repo && cd test-repo && git config user.email "test@test.com" && git config user.name "Test" && \
git checkout -b release && echo "file" > file.txt && git add . && git commit -m "initial" && \
git checkout -b main && echo "change" >> file.txt && git commit -am "change" && \
git log release..main 2>&1 | head -5 && echo "---" && \
git log origin/release..origin/main 2>&1 | head -5Repository: devsy-org/devsy
Length of output: 1243
🏁 Script executed:
# Check if typical commit messages could be problematic
cat <<'EOF'
Examples of problematic commit messages that could cause shell injection:
1. "fix: $(rm -rf /)"
2. "refactor: `dangerous command`"
3. "docs: $(whoami)"
These would be evaluated if passed through bash string interpolation
EOFRepository: devsy-org/devsy
Length of output: 281
Fix shell injection vulnerability in PR body construction.
The --body parameter interpolates commit messages into a bash command string. Commit subjects containing shell metacharacters like $(...) or backticks would be evaluated by the shell before passing to gh pr create, creating a shell injection vector. Use --body-file to bypass shell evaluation:
Suggested patch
- - name: Get commit log
- id: commits
- run: |
- COMMITS=$(git log release..main --oneline)
- {
- echo "log<<EOF"
- echo "$COMMITS"
- echo "EOF"
- } >> "$GITHUB_OUTPUT"
-
- name: Create PR
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
+ {
+ echo "## Commits being promoted"
+ echo
+ git log release..main --oneline
+ } > pr_body.md
+
gh pr create \
--base release \
--head main \
--title "release: promote main to stable" \
- --body "## Commits being promoted
-
- ${{ steps.commits.outputs.log }}"
+ --body-file pr_body.mdNote: The origin/release..origin/main suggestion in the original comment may fail in this workflow. With actions/checkout@v6, branches are local refs. Keep release..main as shown above, or explicitly fetch remote-tracking branches if you want to reference origin/ prefixed refs.
🧰 Tools
🪛 zizmor (1.25.2)
[info] 46-46: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/create-release-pr.yml around lines 26 - 46, Replace the
unsafe inline interpolation of commit text into the gh pr create --body flag
with gh pr create --body-file to avoid shell evaluation; in the "Create PR" step
(env GH_TOKEN, using gh pr create) write the contents of
steps.commits.outputs.log to a securely created temporary file (using a safe
write like printf '%s' or redirect from the steps output) and pass that filename
to --body-file, ensure proper quoting when writing, and remove the temp file
after the command; keep the "Get commit log" step (id: commits) as-is so you can
reference steps.commits.outputs.log for the file contents.
Summary
useExecServer=truefor a growing subset of users. When enabled, it breaks ProxyCommand-based SSH tunnels (like Devsy'sdevsy ssh --stdio) by attempting stdio communication over the same channel the proxy uses.remote.SSH.useExecServer=falsein the host VS Code user settings before opening a remote connection