Skip to content

chore: add docs deploy to publish workflow#542

Merged
zh-lx merged 1 commit into
mainfrom
chore/publish-deploy-workflow
Jun 15, 2026
Merged

chore: add docs deploy to publish workflow#542
zh-lx merged 1 commit into
mainfrom
chore/publish-deploy-workflow

Conversation

@zh-lx

@zh-lx zh-lx commented Jun 15, 2026

Copy link
Copy Markdown
Owner

Summary

  • track deploy.sh and remove it from .gitignore
  • read deploy host/path/password from GitHub secrets
  • run docs deployment after non-dry-run publish workflow

Verification

  • bash -n deploy.sh
  • parsed .github/workflows/publish.yml as YAML

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 15, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (0)

Grey Divider


Action required

1. Deploy runs on dry-run 🐞 Bug ≡ Correctness
Description
In .github/workflows/publish.yml, the new docs deployment steps run unconditionally, so
inputs.dry_run=true still attempts a real docs deployment. This breaks the expected
“non-destructive” dry-run behavior and can unintentionally update docs or fail due to missing
secrets.
Code

.github/workflows/publish.yml[R63-71]

+      - name: Install deploy dependencies
+        run: sudo apt-get update && sudo apt-get install -y sshpass
+
+      - name: Deploy docs
+        env:
+          DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
+          DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
+          SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
+        run: pnpm deploy:docs
Evidence
The workflow defines dry_run and uses it only to switch publish behavior, while the deploy steps
added in this PR have no if: guard and will execute regardless of dry-run mode.

.github/workflows/publish.yml[14-61]
.github/workflows/publish.yml[63-71]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow has a `dry_run` input that only gates the `pnpm publish` command, but the newly added docs deployment steps always run. This makes dry-run executions still deploy docs.

### Issue Context
`inputs.dry_run` is already used in the `Publish packages` step; the deploy steps should follow the same contract and only run when `dry_run` is false.

### Fix Focus Areas
- .github/workflows/publish.yml[55-71]

### Suggested change
Add an `if:` condition to both the `Install deploy dependencies` and `Deploy docs` steps (or wrap them into a single guarded step block), e.g.:

```yaml
- name: Install deploy dependencies
 if: ${{ inputs.dry_run != true }}
 run: ...

- name: Deploy docs
 if: ${{ inputs.dry_run != true }}
 ...
```

Optionally also guard on `secrets.DEPLOY_HOST`/`secrets.DEPLOY_PATH` being present if this workflow may run in environments without those secrets.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. TOFU host key acceptance 🐞 Bug ⛨ Security
Description
deploy.sh uses StrictHostKeyChecking=accept-new, which silently trusts the first host key seen
on the runner (trust-on-first-use). If the network path is intercepted on first connection, the
runner may connect to an impersonated host and upload dist.zip there.
Code

deploy.sh[R8-9]

+ssh_options=(-p "${deploy_port}" -o StrictHostKeyChecking=accept-new)
+scp_options=(-P "${deploy_port}" -o StrictHostKeyChecking=accept-new)
Evidence
The SSH/SCP commands are explicitly configured to accept new host keys automatically via
StrictHostKeyChecking=accept-new.

deploy.sh[7-11]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The deployment client is configured with `StrictHostKeyChecking=accept-new`, which trusts a new/unknown host key automatically. This is weaker than pinning the expected host key and can lead to connecting to the wrong host on first contact.

### Issue Context
This workflow deploys docs artifacts over SSH/SCP from CI. Prefer deterministic host key verification.

### Fix Focus Areas
- deploy.sh[7-12]
- .github/workflows/publish.yml[63-71]

### Suggested change
1. Remove `StrictHostKeyChecking=accept-new`.
2. Pre-populate `~/.ssh/known_hosts` in the workflow using a pinned host key (preferred: store the exact known_hosts line in a secret), e.g.:

```yaml
- name: Configure SSH known_hosts
 run: |
   mkdir -p ~/.ssh
   chmod 700 ~/.ssh
   echo "${{ secrets.DEPLOY_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
   chmod 600 ~/.ssh/known_hosts
```

3. In `deploy.sh`, use `-o StrictHostKeyChecking=yes` (or omit it, since `yes` is default when known_hosts is present) and optionally specify `-o UserKnownHostsFile=~/.ssh/known_hosts`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Bash-only path escaping 🐞 Bug ☼ Reliability
Description
deploy.sh uses printf '%q' to escape DEPLOY_PATH and injects it into the remote script, but
%q produces bash-specific quoting (e.g. $'...') that can fail if the remote user’s shell isn’t
bash. The scp destination also uses ${DEPLOY_PATH} directly, which is fragile for paths containing
spaces/special characters.
Code

deploy.sh[R24-30]

+remote_path="$(printf '%q' "${DEPLOY_PATH}")"
+
+"${scp_cmd[@]}" ./dist.zip "${DEPLOY_HOST}:${DEPLOY_PATH}/dist.zip"
+"${ssh_cmd[@]}" "${DEPLOY_HOST}" << EOF
+  set -e
+  cd ${remote_path}
+  rm -rf cn en
Evidence
The script relies on printf '%q' escaping and then uses the resulting string in a remote cd
command, which is not portable across remote shells; additionally the scp destination concatenates
DEPLOY_PATH without any robust escaping strategy.

deploy.sh[24-33]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The script builds `remote_path` using `printf '%q'` and then runs `cd ${remote_path}` on the remote. `%q` output is bash-specific and may not be interpreted correctly by non-bash remote shells, breaking deployments for certain servers/paths.

### Issue Context
`pnpm deploy:docs` invokes `bash ./deploy.sh` from CI, and the script runs remote commands via `ssh` heredoc.

### Fix Focus Areas
- deploy.sh[24-33]

### Suggested change
Use a POSIX-safe single-quote escaping helper and ensure the remote side is executed by a known shell.

Option A (force bash remotely):
- Run `ssh host bash -s <<'EOF'` and pass the path via environment or positional args.

Option B (POSIX quoting):
- Escape `DEPLOY_PATH` for single quotes and use `cd -- '...escaped...'`.

Also apply the same safe escaping to the remote scp target path (remote scp typically involves a remote shell invocation), so paths with spaces don’t break.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

4. Always installs sshpass 🐞 Bug ➹ Performance
Description
The publish workflow always installs sshpass, even though deploy.sh only requires it when
SERVER_PASSWORD is set. This adds avoidable CI time and an unnecessary package when key-based auth
is used.
Code

.github/workflows/publish.yml[R63-65]

+      - name: Install deploy dependencies
+        run: sudo apt-get update && sudo apt-get install -y sshpass
+
Evidence
deploy.sh conditionally requires sshpass only when SERVER_PASSWORD is set, but the workflow
step installs it regardless.

deploy.sh[13-22]
.github/workflows/publish.yml[63-65]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow installs `sshpass` unconditionally, but the deploy script only needs it when password auth is used.

### Issue Context
`deploy.sh` checks for `sshpass` only when `SERVER_PASSWORD` is non-empty.

### Fix Focus Areas
- .github/workflows/publish.yml[63-65]
- deploy.sh[13-22]

### Suggested change
Add an `if:` guard to the `sshpass` install step, e.g. install only when `${{ secrets.SERVER_PASSWORD }}` is set/non-empty, or split deployment into key-based vs password-based paths.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Deploy docs after publish via GitHub Actions using deploy.sh and secrets
✨ Enhancement ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

Walkthroughs

Description
• Add a docs deployment step to the publish GitHub Actions workflow after real publishes.
• Introduce a deploy.sh script that uploads and unpacks docs artifacts on a remote host.
• Read deploy host/path/password from GitHub Secrets and install sshpass when needed.
Diagram
graph TD
  A["GitHub Actions: publish.yml"] --> B["Install sshpass"] --> C["Deploy docs (pnpm deploy:docs)"] --> D["deploy.sh"] --> E{{"Remote docs host"}}
  S[("GitHub Secrets")] --> C
  C --> Z["dist.zip"] --> D

  subgraph Legend
    direction LR
    _wf["Workflow step"] ~~~ _sec[("Secret store")] ~~~ _ext{{"External system"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use SSH key auth (no sshpass/password)
  • ➕ Avoids password-based SSH and reduces secret exposure risk
  • ➕ No need to install sshpass on runners
  • ➕ Common, well-supported pattern with ssh-agent
  • ➖ Requires managing a deploy key and server-side authorized_keys
  • ➖ Key rotation/permissions need operational ownership
2. Use a purpose-built deploy action (e.g., rsync/ssh deploy action)
  • ➕ Less custom scripting to maintain
  • ➕ Often provides hardened defaults and better logging
  • ➖ Additional dependency on third-party action behavior and updates
  • ➖ May be less flexible than a bespoke script

Recommendation: The current approach (explicit deploy.sh invoked from publish.yml) is reasonable for a custom remote-host deployment and keeps the behavior transparent. If feasible, prefer SSH key-based auth over sshpass/password to reduce security risk and simplify runner setup; the workflow structure can remain the same with only credential handling changed.

Grey Divider

File Changes

Other (2)
publish.yml Run docs deployment after publish and install sshpass +10/-0

Run docs deployment after publish and install sshpass

• Adds two new steps to the publish workflow: install sshpass and run a docs deployment command. Wires DEPLOY_HOST/DEPLOY_PATH/SERVER_PASSWORD via GitHub Secrets for use during deployment.

.github/workflows/publish.yml


deploy.sh Add SSH/SCP-based docs deployment script for dist.zip +33/-0

Add SSH/SCP-based docs deployment script for dist.zip

• Introduces a bash script that validates required deploy env vars, optionally wraps ssh/scp with sshpass when a password is provided, uploads dist.zip, and unzips it on the remote host after clearing existing locale directories.

deploy.sh


Grey Divider

Qodo Logo

Comment on lines +63 to +71
- name: Install deploy dependencies
run: sudo apt-get update && sudo apt-get install -y sshpass

- name: Deploy docs
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
run: pnpm deploy:docs

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Deploy runs on dry-run 🐞 Bug ≡ Correctness

In .github/workflows/publish.yml, the new docs deployment steps run unconditionally, so
inputs.dry_run=true still attempts a real docs deployment. This breaks the expected
“non-destructive” dry-run behavior and can unintentionally update docs or fail due to missing
secrets.
Agent Prompt
### Issue description
The workflow has a `dry_run` input that only gates the `pnpm publish` command, but the newly added docs deployment steps always run. This makes dry-run executions still deploy docs.

### Issue Context
`inputs.dry_run` is already used in the `Publish packages` step; the deploy steps should follow the same contract and only run when `dry_run` is false.

### Fix Focus Areas
- .github/workflows/publish.yml[55-71]

### Suggested change
Add an `if:` condition to both the `Install deploy dependencies` and `Deploy docs` steps (or wrap them into a single guarded step block), e.g.:

```yaml
- name: Install deploy dependencies
  if: ${{ inputs.dry_run != true }}
  run: ...

- name: Deploy docs
  if: ${{ inputs.dry_run != true }}
  ...
```

Optionally also guard on `secrets.DEPLOY_HOST`/`secrets.DEPLOY_PATH` being present if this workflow may run in environments without those secrets.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (eef3093) to head (eeed7df).

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #542   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           26        26           
  Lines         5579      5579           
  Branches      1547      1547           
=========================================
  Hits          5579      5579           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@zh-lx
zh-lx merged commit 77e12f3 into main Jun 15, 2026
5 checks passed
@zh-lx
zh-lx deleted the chore/publish-deploy-workflow branch June 15, 2026 01:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant