Add deploy verification guards - #8
Conversation
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_3328a426-ff72-4110-8fac-01d3e629cdf7) |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis change adds Bash validation CI, scheduled Cloudflare Pages deployment verification, Wrangler configuration, and a safety gate requiring schema-triggered deployments to use a current clean checkout. ChangesDeployment safety and verification
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant VerifyWorkflow
participant VerificationScript
participant GitRemote
participant CloudflarePages
VerifyWorkflow->>VerificationScript: Run verification with Cloudflare settings
VerificationScript->>GitRemote: Fetch configured branch and resolve HEAD
VerificationScript->>CloudflarePages: List Pages deployments as JSON
CloudflarePages-->>VerificationScript: Return production deployment metadata
VerificationScript-->>VerifyWorkflow: Report matching or mismatching commit
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
fe443fe to
2479492
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_e2d5c427-53a9-4665-9f37-204f73492270) |
| if command -v wrangler >/dev/null 2>&1; then | ||
| wrangler "$@" | ||
| else | ||
| npx --yes wrangler "$@" |
There was a problem hiding this comment.
This fallback downloads and executes whatever wrangler version npm currently serves while the workflow has CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_ID in its environment. Because the PR adds no package.json/lockfile or version pin, a compromised npm release or dependency would run with those credentials. Pin wrangler through a lockfile-backed install (npm ci before exporting secrets, then execute the local binary) or otherwise pin the exact package version/integrity, and keep the workflow token read-only.
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/ci.yml (1)
1-20: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low valueHarden workflow permissions/pinning per zizmor findings.
No top-level
permissions:block (defaults to broad token scopes),actions/checkout@v4isn't pinned to a commit SHA, andpersist-credentialsisn't disabled. Low risk here since this job only runsbash -nwith no secrets, but cheap to fix.🔧 Proposed fix
name: Deploy CI +permissions: + contents: read + on: push: branches: [main] pull_request: branches: [main] jobs: shell-syntax: name: Shell Syntax runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v4 # consider pinning to a commit SHA + with: + persist-credentials: false🤖 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/ci.yml around lines 1 - 20, Add a top-level permissions block restricting the workflow token to read-only access, pin the actions/checkout step to a full commit SHA instead of the mutable `@v4` tag, and set persist-credentials: false for that checkout. Apply these changes in the shell-syntax job without altering its Bash validation behavior.Source: Linters/SAST tools
🤖 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/ci.yml:
- Around line 3-7: Add a top-level concurrency group to the workflow alongside
the existing on triggers, using a workflow- and ref-based group key and
cancel-in-progress enabled so obsolete runs are canceled instead of queued.
In @.github/workflows/verify-deployed.yml:
- Around line 3-6: Add a workflow-level concurrency group to the verification
workflow, covering both the scheduled and workflow_dispatch triggers. Configure
it to use a stable group name and cancel or prevent overlapping runs so
duplicate verifications cannot execute concurrently.
- Around line 13-21: Pin the actions used in the deployment verification job to
immutable commit SHAs instead of floating v4 tags, including actions/checkout
and actions/setup-node; update the checkout configuration to set
persist-credentials: false while retaining fetch-depth: 0, and preserve the
existing Node 20 setup.
In `@scripts/allium-deploy-update.sh`:
- Around line 48-52: Update require_current_deploy_checkout so it does not
permanently change the caller’s working directory: run the checkout verification
commands in a subshell or use git’s directory option. Add a bounded timeout to
the git fetch invocation so network hangs cannot stall deployment indefinitely.
In `@scripts/verify-deployed-matches-checkout.sh`:
- Around line 24-30: Update the jq selector used by the deployment verification
logic to reference the exact case-sensitive Environment, Branch, and Source
fields emitted by wrangler pages deployment list --json, so DEPLOYED_SHA is
populated correctly; also pin the wrangler version used by run_wrangler for
stable output schema.
---
Outside diff comments:
In @.github/workflows/ci.yml:
- Around line 1-20: Add a top-level permissions block restricting the workflow
token to read-only access, pin the actions/checkout step to a full commit SHA
instead of the mutable `@v4` tag, and set persist-credentials: false for that
checkout. Apply these changes in the shell-syntax job without altering its Bash
validation behavior.
🪄 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: ASSERTIVE
Plan: Pro
Run ID: f48a5afa-2e55-43ce-8eaa-53d749a3960e
📒 Files selected for processing (4)
.github/workflows/ci.yml.github/workflows/verify-deployed.ymlscripts/allium-deploy-update.shscripts/verify-deployed-matches-checkout.sh
| require_current_deploy_checkout() { | ||
| log "Verifying allium-deploy checkout before schema-triggered deploy..." | ||
|
|
||
| cd "$DEPLOY_DIR" | ||
| git fetch --quiet origin main |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: confirm whether `set -e`/pipefail is active and how DEPLOY_DIR is defined earlier in the file.
fd 'allium-deploy-update.sh' scripts --exec sed -n '1,45p' {}Repository: 1aeo/allium-deploy
Length of output: 1630
Avoid changing cwd in the guard and add a fetch timeout.
cd "$DEPLOY_DIR" mutates the shell’s working directory for the rest of the script, so this helper isn’t side-effect-free. git fetch --quiet origin main also has no timeout, which can stall the deploy path indefinitely if the network hangs.
🤖 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 `@scripts/allium-deploy-update.sh` around lines 48 - 52, Update
require_current_deploy_checkout so it does not permanently change the caller’s
working directory: run the checkout verification commands in a subshell or use
git’s directory option. Add a bounded timeout to the git fetch invocation so
network hangs cannot stall deployment indefinitely.
There was a problem hiding this comment.
Stale comment
Security review
No high-confidence vulnerabilities found in the current diff.
I specifically reviewed the newly added GitHub Actions workflows, Cloudflare Pages verification script, deploy-checkout guard, and new
wranglerdependency/lockfile handling. The prior unpinnedwranglerconcern appears addressed: the workflow now installs an exactwranglerversion frompnpm-lock.yamlbefore Cloudflare credentials are exposed, and the credentialed verifier step uses the local installed binary.pnpm audit --audit-level highalso reported no known high-severity advisories.Residual hardening to consider, but not a confirmed vulnerability from this diff: pin GitHub Actions to immutable commit SHAs for stronger supply-chain defense.
Sent by Cursor Automation: Find vulnerabilities
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
scripts/verify-deployed-matches-checkout.sh (1)
57-67: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAdd a timeout to the remote fetch.
The fetch here has no bound, unlike the fetch in
scripts/allium-deploy-update.sh(wrapped inrun_with_timeoutin this same PR). A network hang would stall this check indefinitely.⏱️ Suggested fix
-git fetch --quiet "$REMOTE" "$BRANCH" +run_with_timeout 30 git fetch --quiet "$REMOTE" "$BRANCH"🤖 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 `@scripts/verify-deployed-matches-checkout.sh` around lines 57 - 67, Wrap the git fetch in the verification script with the existing run_with_timeout helper, using the same timeout convention as scripts/allium-deploy-update.sh, while preserving the current quiet remote and branch arguments.
🤖 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.
Outside diff comments:
In `@scripts/verify-deployed-matches-checkout.sh`:
- Around line 57-67: Wrap the git fetch in the verification script with the
existing run_with_timeout helper, using the same timeout convention as
scripts/allium-deploy-update.sh, while preserving the current quiet remote and
branch arguments.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: ccd3ce48-6075-4a80-b0eb-3e7ed4ff9943
📒 Files selected for processing (2)
scripts/allium-deploy-update.shscripts/verify-deployed-matches-checkout.sh
There was a problem hiding this comment.
Stale comment
Security review
No high-confidence vulnerabilities found in the current diff.
Reviewed areas:
- GitHub Actions workflows: tokens are restricted to
contents: read, checkout credentials are not persisted, and actions are pinned by commit SHA.- Cloudflare Pages verifier: credentials are only supplied to the verification step after dependencies are installed from the checked-in pnpm lockfile, and the script uses the local pinned
wranglerbinary when available.- Deploy guard changes: the schema-triggered deploy path now requires the deploy checkout to match
origin/mainand have a clean working tree before running the Pages deploy script.- Dependency surface:
wrangleris exact-version pinned inpackage.json/pnpm-lock.yaml;pnpm audit --audit-level highreported no known high-severity advisories.The prior unpinned
wranglersupply-chain concern appears addressed in this head revision.Sent by Cursor Automation: Find vulnerabilities
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/ci.yml (1)
16-28: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider adding ShellCheck for deeper validation.
bash -nonly catches syntax errors, not common bash pitfalls (unquoted expansions, unset variables, etc.) inscripts/allium-deploy-update.shandscripts/verify-deployed-matches-checkout.sh. Adding ashellcheckstep alongside the syntax check would catch more classes of bugs in these deploy-critical scripts.♻️ Proposed addition
- name: Check Bash scripts run: | find scripts -name '*.sh' -print0 | xargs -0 -n1 bash -n + + - name: ShellCheck + uses: ludeeus/shellcheck-action@2.0.0 + with: + scandir: './scripts'🤖 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/ci.yml around lines 16 - 28, Add a ShellCheck validation step to the shell-syntax job alongside the existing bash -n check, targeting scripts/allium-deploy-update.sh and scripts/verify-deployed-matches-checkout.sh (or all scripts/*.sh) and ensuring ShellCheck is available on the runner before execution.
🤖 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.
Outside diff comments:
In @.github/workflows/ci.yml:
- Around line 16-28: Add a ShellCheck validation step to the shell-syntax job
alongside the existing bash -n check, targeting scripts/allium-deploy-update.sh
and scripts/verify-deployed-matches-checkout.sh (or all scripts/*.sh) and
ensuring ShellCheck is available on the runner before execution.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1e755944-bc8b-4e36-b309-829ca19c0374
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
.github/workflows/ci.yml.github/workflows/verify-deployed.yml.gitignorepackage.jsonpnpm-workspace.yamlscripts/verify-deployed-matches-checkout.sh
bd7fa03 to
2ee4fd7
Compare
There was a problem hiding this comment.
Stale comment
Security review
No high-confidence vulnerabilities found in this PR.
Reviewed areas:
- GitHub Actions permissions and secret exposure: new workflows use
contents: read; Cloudflare secrets are only passed to the scheduled/manual verification step, not the PR CI path.- Shell command construction: newly added/changed commands quote environment-controlled values and avoid obvious command/path injection in the deploy verification paths.
- Dependency/supply-chain changes:
wrangleris pinned inpackage.json/pnpm-lock.yaml, GitHub Actions are pinned by commit SHA, andpnpm audit --audit-level lowreports no known vulnerabilities.Residual note: the new verification workflow executes the checked-in verifier with Cloudflare credentials on scheduled/manual runs, so continue treating dependency updates and future verifier-script changes as privileged-code changes.
Sent by Cursor Automation: Find vulnerabilities
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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/verify-deployed.yml:
- Around line 37-50: Move the Cloudflare secret preflight before Node setup and
the “Install verifier dependencies” step, then expose its result through a job
or step output. Condition Node setup, dependency installation, and “Verify
deployed Pages commit” on that result, while retaining the notice and clean exit
when secrets are absent.
- Around line 28-32: Reorder the workflow steps so pnpm is enabled before the
“Set up Node” step using actions/setup-node; use the existing pnpm setup
mechanism or add pnpm/action-setup, ensuring pnpm is available on PATH before
setup-node’s pnpm cache initialization.
In `@scripts/verify-deployed-matches-checkout.sh`:
- Around line 78-80: Bound the Wrangler deployment-list request with a timeout.
Update the command assigning DEPLOYMENTS_JSON to invoke run_with_timeout around
run_wrangler pages deployment list, preserving the existing project name and
JSON arguments and using the script’s established timeout convention.
- Around line 78-80: Add the `--environment production` flag to the
`run_wrangler pages deployment list` invocation used to populate
`DEPLOYMENTS_JSON`, ensuring Wrangler filters for production deployments
server-side.
- Around line 112-116: The production deployment selector must exclude failed or
canceled entries before choosing a deployment. Update the selector in the
deployment lookup pipeline to require .latest_stage.status == "success"
alongside the existing production branch/environment conditions, then read
Source only from that filtered result.
🪄 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: ASSERTIVE
Plan: Pro
Run ID: 42e72adf-6aeb-45c2-9d14-66ee99fd730a
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (7)
.github/workflows/ci.yml.github/workflows/verify-deployed.yml.gitignorepackage.jsonpnpm-workspace.yamlscripts/allium-deploy-update.shscripts/verify-deployed-matches-checkout.sh
| - name: Set up Node | ||
| uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 | ||
| with: | ||
| node-version: '24' | ||
| cache: 'pnpm' |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the workflow around the cited lines.
git ls-files .github/workflows/verify-deployed.yml
echo '---'
cat -n .github/workflows/verify-deployed.yml | sed -n '1,220p'
echo '--- SEARCH corepack/pnpm/setup-node references ---'
rg -n "corepack|pnpm|setup-node|cache:" .github/workflows/verify-deployed.ymlRepository: 1aeo/allium-deploy
Length of output: 2221
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the workflow file and inspect the relevant job section only.
awk 'NR>=1 && NR<=220 {print NR ":" $0}' .github/workflows/verify-deployed.ymlRepository: 1aeo/allium-deploy
Length of output: 1707
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/verify-deployed.yml')
text = p.read_text()
print(text)
PYRepository: 1aeo/allium-deploy
Length of output: 1567
🏁 Script executed:
#!/bin/bash
set -euo pipefail
cat -n .github/workflows/verify-deployed.yml | sed -n '1,220p'Repository: 1aeo/allium-deploy
Length of output: 1916
🏁 Script executed:
#!/bin/bash
set -euo pipefail
cat -n .github/workflows/verify-deployed.yml | sed -n '1,200p'Repository: 1aeo/allium-deploy
Length of output: 1916
🌐 Web query:
actions/setup-node pnpm cache requires pnpm on PATH setup-node before corepack enable
💡 Result:
Yes, using the caching feature in actions/setup-node with pnpm requires that the pnpm executable be available on the system PATH at the time the action runs [1][2]. If you attempt to use the caching feature (either via explicit configuration or automatic detection) before pnpm is installed and added to the PATH, the action will fail with an error stating that the pnpm executable cannot be located [1][2]. To resolve this and correctly use caching with pnpm, you have two primary approaches: 1. Recommended Approach: Use pnpm/action-setup The most reliable method is to install pnpm using the official pnpm/action-setup action before running actions/setup-node [3][2]. This ensures that the pnpm binary is present on the PATH and ready for the caching logic to interact with it [3]. Example: - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: cache: pnpm 2. Corepack Approach If you prefer using Corepack, you must enable it and ensure the specific version of pnpm is prepared before the actions/setup-node step [4][5]. Because actions/setup-node checks for the pnpm executable during its execution, the Corepack environment must be fully initialized beforehand [1][2]. Note on Automatic Caching In newer versions of actions/setup-node (v5 and later), the action may attempt to automatically enable caching if it detects a packageManager field in your package.json [1][2]. If you are not yet ready to set up pnpm on the PATH or are experiencing issues with automatic caching, you can disable this behavior by setting the following input in your actions/setup-node step [1][2]: with: package-manager-cache: false This prevents the action from failing due to the missing executable, allowing you to configure caching manually or use alternative methods [1][2].
Citations:
- 1: Action failing since
package-manager-cacheadded actions/setup-node#1351 - 2: v5 fails immediately when using
pnpmactions/setup-node#1357 - 3: Use actions/setup-node to cache pnpm store instead of doing it manually pnpm/action-setup#76
- 4: https://pnpm.io/continuous-integration
- 5: https://nodejs.org/docs/v22.14.0/api/corepack.html
Move pnpm setup before setup-node.
actions/setup-node runs pnpm caching before corepack enable, so the cache step can fail because pnpm isn’t on PATH yet. Enable pnpm first (or use pnpm/action-setup), then run setup-node.
🤖 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/verify-deployed.yml around lines 28 - 32, Reorder the
workflow steps so pnpm is enabled before the “Set up Node” step using
actions/setup-node; use the existing pnpm setup mechanism or add
pnpm/action-setup, ensuring pnpm is available on PATH before setup-node’s pnpm
cache initialization.
Source: MCP tools
2ee4fd7 to
e27fd84
Compare
| - name: Verify deployed Pages commit | ||
| if: steps.cloudflare-secrets.outputs.available == 'true' | ||
| env: | ||
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | ||
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | ||
| PAGES_PROJECT_NAME: ${{ vars.PAGES_PROJECT_NAME || '1aeo-metrics' }} | ||
| run: | | ||
| ./scripts/verify-deployed-matches-checkout.sh |
There was a problem hiding this comment.
This secret-bearing step runs ./scripts/verify-deployed-matches-checkout.sh from the ref checked out earlier. Because the workflow also has workflow_dispatch, a user with permission to manually run Actions can select their own branch/ref; that branch can modify this script and run with CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_ID in the environment. Please either remove manual dispatch or force secret-bearing runs to check out trusted main code and gate the job to main (ideally with a protected Environment for the Cloudflare token).
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/ci.yml:
- Around line 30-38: Update the “ShellCheck deploy scripts” step in the workflow
to lint the same complete set of shell scripts covered by the syntax-check step,
rather than hardcoding two filenames. Use a glob or dynamically discovered list
for all scripts/*.sh files, preserving the existing ShellCheck exclusions and
execution flags so newly added scripts are automatically included.
🪄 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: ASSERTIVE
Plan: Pro
Run ID: 586cc6a6-e530-4c51-a498-8daa8d5ee9ae
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (7)
.github/workflows/ci.yml.github/workflows/verify-deployed.yml.gitignorepackage.jsonpnpm-workspace.yamlscripts/allium-deploy-update.shscripts/verify-deployed-matches-checkout.sh
There was a problem hiding this comment.
Security review result: no high-confidence vulnerabilities found in this diff.
I reviewed the added GitHub Actions workflows, deploy verification scripts, shell changes, and new pnpm dependency surface for injection, permission-boundary mistakes, secret exposure, and supply-chain risk. The workflows use read-only repository permissions and disabled checkout credential persistence, Cloudflare secrets are only passed to the verification steps that need them, shell arguments in the added scripts are quoted, and pnpm audit --audit-level moderate reported no known vulnerabilities.
Sent by Cursor Automation: Find vulnerabilities


Summary
Notes
config.env, logs, and generatedwrangler.tomlremain allowed.Validation
find scripts -name '*.sh' -print0 | xargs -0 -n1 bash -n\n-bash -n scripts/verify-deployed-matches-checkout.sh\n- YAML parse for.github/workflows/*.yml\n- jq extraction check against sample deployment JSON\n-git diff --check\n- PII/secrets grep: no real secrets found; existing placeholders onlySummary by CodeRabbit
node_modules/in Git.