ci: merge main into production before deploy#107
Conversation
📝 WalkthroughWalkthroughA new GitHub Actions workflow automatically syncs the ChangesProduction sync workflow
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 648d6d62c6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e7c82f988f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
.github/workflows/sync-main-to-production.yml (1)
17-17: 💤 Low valueRedundant condition check.
The
ifcondition is redundant since the workflow is already filtered to only trigger on pushes tomain(lines 4-6). The condition adds no additional safety.♻️ Optional: Remove redundant condition
runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' steps:🤖 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/sync-main-to-production.yml at line 17, The workflow contains a redundant runtime conditional "if: github.ref == 'refs/heads/main'" that duplicates the push trigger filter; remove that "if: github.ref == 'refs/heads/main'" line (the runtime conditional) so the job relies on the workflow-level triggers instead, leaving the rest of the job steps and names (the job block using that if) unchanged.
🤖 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/sync-main-to-production.yml:
- Around line 25-35: The current step uses git merge then git push (git merge /
git push origin production), which both diverges from the intent of making
production point at main and is fragile to races; replace the merge/push
sequence with a force-with-lease sync so production mirrors main by using a push
that updates production to main's commit (use git push --force-with-lease origin
main:production) while preserving the existing safety flags (set -euo pipefail)
— alternatively, if you truly want to keep a merge strategy, keep the merge but
add --force-with-lease to the git push to mitigate races.
- Line 20: Replace the floating tag for the checkout action by pinning it to the
v6 tag’s commit SHA: find the workflow step that currently says "uses:
actions/checkout@v6" and change it to use the exact commit SHA
"de0fac2e4500dabe0009e67214ff5f5447ce83dd" so the checkout action is fixed to
that immutable revision; do not change the persist-credentials behavior (leave
default) since the job performs a git push.
---
Nitpick comments:
In @.github/workflows/sync-main-to-production.yml:
- Line 17: The workflow contains a redundant runtime conditional "if: github.ref
== 'refs/heads/main'" that duplicates the push trigger filter; remove that "if:
github.ref == 'refs/heads/main'" line (the runtime conditional) so the job
relies on the workflow-level triggers instead, leaving the rest of the job steps
and names (the job block using that if) unchanged.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 8c7acd86-fb69-4fbd-89e9-ff9cafc0f559
📒 Files selected for processing (1)
.github/workflows/sync-main-to-production.yml
| if: github.ref == 'refs/heads/main' | ||
| steps: | ||
| - name: Checkout main | ||
| uses: actions/checkout@v6 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Get the latest commit hash for actions/checkout@v6
gh api repos/actions/checkout/git/ref/tags/v6 --jq '.object.sha'Repository: foldaway/mrtdown-site
Length of output: 106
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE=".github/workflows/sync-main-to-production.yml"
echo "== Snippet around checkout@v6 =="
nl -ba "$FILE" | sed -n '1,120p' | sed -n '15,40p'
echo
echo "== Lines containing actions/checkout =="
rg -n "actions/checkout" "$FILE" || true
echo
echo "== Lines containing persist-credentials =="
rg -n "persist-credentials" "$FILE" || trueRepository: foldaway/mrtdown-site
Length of output: 159
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE=".github/workflows/sync-main-to-production.yml"
echo "== Quick existence check =="
test -f "$FILE" && echo "Found $FILE" || (echo "Missing $FILE" && exit 1)
echo
echo "== Lines 15-40 (with line numbers via awk) =="
awk 'NR>=15 && NR<=40 {printf "%d:%s\n", NR, $0}' "$FILE"
echo
echo "== Lines containing actions/checkout (anywhere in file) =="
rg -n "actions/checkout" "$FILE" || true
echo
echo "== Lines containing persist-credentials (anywhere in file) =="
rg -n "persist-credentials" "$FILE" || trueRepository: foldaway/mrtdown-site
Length of output: 1218
🌐 Web query:
actions/checkout persist-credentials default value true false
💡 Result:
The default value for the persist-credentials input in the actions/checkout action is true [1][2][3]. When set to true (the default), the action configures the authentication token or SSH key with the local git configuration [1][3]. This allows subsequent steps in the job to execute authenticated git commands (such as git fetch or git push) automatically [1][2]. To prevent these credentials from being persisted in the local git configuration, you must explicitly set persist-credentials to false in your workflow file [1][4].
Citations:
- 1: https://github.com/actions/checkout/?tab=readme-ov-file
- 2: https://github.com/actions/checkout/tree/refs/heads/main
- 3: https://spacelift.io/blog/github-actions-checkout
- 4: https://yossarian.net/til/post/actions-checkout-can-leak-github-credentials/
🌐 Web query:
actions/checkout persist-credentials false git push fetch subsequent steps
💡 Result:
In GitHub Actions, setting actions/checkout with persist-credentials: false removes the need for the checkout-provided token to be written to the runner’s local git configuration; as a result, subsequent steps will not have authenticated access for git push unless you provide credentials another way. Git’s authenticated commands (like git fetch/git push) will “just work” only when checkout has persisted credentials; otherwise they need explicit authentication configuration.[1] What to watch for in the common patterns: 1) git push in subsequent steps requires credentials - actions/checkout documents that the auth token is persisted in the local git config to enable “authenticated git commands” in later steps, and you can opt out with persist-credentials: false.[1] - Therefore, if you set persist-credentials: false, a later git push will typically fail unless you re-authenticate (e.g., by configuring a remote URL that embeds a token, adding SSH keys/known_hosts + configuring SSH, or using a different credential mechanism) because checkout no longer configures the token/credentials for git automatically.[1] 2) git fetch behavior - While checkout still performs the initial fetch during the action run, your “subsequent steps” that run git fetch are also affected by whether credentials were persisted.[1] - If your later git fetch targets private remotes requiring auth, you will similarly need to provide credentials explicitly when persist-credentials: false is used.[1] 3) Security rationale - The persist-credentials input is specifically about whether checkout configures the token/SSH key with the local git config (default true) and can be disabled to reduce credential persistence across steps.[1] Practical guidance (summary) - If you need to run git push (or authenticated git fetch) in later steps, do not rely on actions/checkout’s persisted credentials when you set persist-credentials: false; instead, add an explicit authentication step or provide credentials/configuration directly for the later git command.[1] - If you only need repository contents for read-only tasks, set persist-credentials: false to avoid leaving credentials configured for subsequent steps.[1]
Citations:
Pin actions/checkout to a commit SHA (supply-chain hardening).
- In
.github/workflows/sync-main-to-production.yml, replaceuses: actions/checkout@v6with the v6 tag’s commit SHAde0fac2e4500dabe0009e67214ff5f5447ce83dd. - The “persist-credentials” warning is acceptable here: the workflow runs
git push origin production, andactions/checkoutdefaultspersist-credentialstotrue; setting it tofalsewould typically break the push unless credentials are reconfigured.
🧰 Tools
🪛 zizmor (1.25.2)
[error] 20-20: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 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/sync-main-to-production.yml at line 20, Replace the
floating tag for the checkout action by pinning it to the v6 tag’s commit SHA:
find the workflow step that currently says "uses: actions/checkout@v6" and
change it to use the exact commit SHA "de0fac2e4500dabe0009e67214ff5f5447ce83dd"
so the checkout action is fixed to that immutable revision; do not change the
persist-credentials behavior (leave default) since the job performs a git push.
| - name: Merge main into production | ||
| run: | | ||
| set -euo pipefail | ||
|
|
||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
|
|
||
| git fetch origin main production | ||
| git switch -C production origin/production | ||
| git merge --no-edit origin/main | ||
| git push origin production |
There was a problem hiding this comment.
Implementation diverges from stated intent; merge will fail if production has diverged.
The PR description states the workflow "pushes that commit directly to production," but the implementation uses git merge. This creates two problems:
- Semantic mismatch: A merge creates a new merge commit and combines histories, rather than making production point to the same commit as main.
- Fragile to divergence: If production ever has commits not in main (e.g., emergency hotfixes, reverts, or concurrent pushes), the merge will fail without a conflict resolution strategy.
Additionally, the push is vulnerable to race conditions—if another process pushes to production between your fetch and push, this will fail.
Choose one approach:
Option A (true sync—production always mirrors main):
- name: Sync main to production
run: |
set -euo pipefail
git push --force-with-lease origin main:productionOption B (merge—production accumulates main's changes):
Keep the current approach but add --force-with-lease to handle races:
git merge --no-edit origin/main
- git push origin production
+ git push --force-with-lease origin production🤖 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/sync-main-to-production.yml around lines 25 - 35, The
current step uses git merge then git push (git merge / git push origin
production), which both diverges from the intent of making production point at
main and is fragile to races; replace the merge/push sequence with a
force-with-lease sync so production mirrors main by using a push that updates
production to main's commit (use git push --force-with-lease origin
main:production) while preserving the existing safety flags (set -euo pipefail)
— alternatively, if you truly want to keep a merge strategy, keep the merge but
add --force-with-lease to the git push to mitigate races.
Motivation
productionup to date withmainso production deploys can run after changes land onmain.Description
/.github/workflows/sync-main-to-production.ymlwhich triggers on pushes tomainand on manualworkflow_dispatch.main, switches to the remoteproductionbranch, mergesorigin/main, and pushesproduction.productionalready has commits not present onmain.deploy.ymlon theproductionref after syncing, because pushes made byGITHUB_TOKENdo not trigger downstream push workflows.Testing
npm run verifyCodex Task
Summary by CodeRabbit