feat(ci): add comment on pr workflow by riteshfyi · Pull Request #663 · webex/widgets
Code Review
Great feature idea — the UX shown in the test comment (riteshfyi#5) looks clean and helpful for contributors. A few issues need to be addressed before this is production-ready, ranging from a security concern to reliability gaps.
🔴 High — Script injection via template literal in github-script
In the Post Release Comment on PR step:
const raw = `${{ needs.publish-npm.outputs.package_versions }}`;
GitHub Actions interpolates ${{ ... }} expressions before the script is executed, so the value of package_versions is injected verbatim into the JavaScript source. If yarn package-tools increment ever emits a backtick or a ${...} sequence (e.g., in a package name or log line), it breaks out of the template literal. GitHub's own security hardening guide recommends passing untrusted step outputs through intermediate environment variables:
- name: Post Release Comment on PR if: steps.get-pr.outputs.pr_number != '' env: PACKAGE_VERSIONS: ${{ needs.publish-npm.outputs.package_versions }} PR_NUMBER: ${{ steps.get-pr.outputs.pr_number }} uses: actions/github-script@v7 with: script: | const prNumber = parseInt(process.env.PR_NUMBER); const raw = process.env.PACKAGE_VERSIONS; // rest of logic unchanged
The same pattern applies to '${{ steps.get-pr.outputs.pr_number }}' on the parseInt line.
🟡 Medium — Release tag URLs will 404
The comment generates links like:
`[\`${tag}\`](${repoUrl}/releases/tag/${tag})`The publish-tag job only creates and pushes annotated Git tags — it does not create GitHub Release objects (no gh release create step). GitHub's releases/tag/<tag> URL returns a 404 (or a sparse stub) for tags that have no associated Release. Either:
- Change the links to point to the tag tree:
`${repoUrl}/tree/${tag}`, or - Add a
gh release create "$TAG_NAME" --generate-notescall inpublish-tagafter each successful tag push.
This was also flagged by the automated Codex review.
🟡 Medium — Fragile bash pipe for capturing package_versions
echo "$OUTPUT" | while IFS= read -r line; do if echo "$line" | grep -q ' => '; then echo "__webex_release__: $line" fi done >> $GITHUB_OUTPUT
This relies on the undocumented output format of yarn package-tools increment. Any change to that tool's output (e.g. a new progress or debug line containing =>) would silently corrupt the parsed versions. Additionally, without set -o pipefail, a failure inside the pipe won't fail the step. Prefer having package-tools emit structured JSON, or at minimum add set -euo pipefail at the top of the run block.
🟡 Medium — Version extraction in publish-tag is undocumented and fragile
VERSION=$(yarn package-tools sync --tag ${GITHUB_REF##*/} --packages "$TAGGABLE_PKG" | awk '{print $3}' | tr -d '%' | head -1)The $3 column and % stripping are tied to a specific output format of yarn package-tools sync that is not documented here. If the tool output changes, tags will silently be created with empty or wrong version strings. Reading the version directly from package.json after the sync step would be more reliable:
VERSION=$(node -p "require('./packages/path-to-pkg/package.json').version")🟡 Medium — Unquoted expression expansion in run: steps
Several existing run: steps embed ${{ ... }} expressions directly in shell without quotes:
OUTPUT=$(yarn package-tools increment --packages ${{ needs.analyze-changes.outputs.node-recursive }} --tag ${GITHUB_REF##*/})The node-recursive output is a JSON array. While the source is internal, direct expression injection into shells is a pattern GitHub flags as risky. Pass the value through an env: variable at the step level and reference $PACKAGES in the shell script.
🟢 Low — comment-on-pr runs even when nothing was published
The job condition is:
needs: [publish-npm, publish-tag]
but there's no if: guard checking needs.publish-npm.outputs.published == 'true'. The script handles the no-packages case gracefully, but it still queries GitHub's API on every push. Adding a job-level condition avoids unnecessary API calls.
🟢 Low — Changelog stable_version stripping is too broad
const stableVersion = ver.replace(/-.*$/, '');
This converts 1.28.0-next.33 → 1.28.0, which is correct for next pre-releases. But it would also turn 2.0.0-rc.0 → 2.0.0 or 1.28.0-alpha.1 → 1.28.0, which may point to the wrong changelog entry. Consider making this logic explicit for the known release tracks, or parameterizing it.
🟢 Low — Comment deduplication relies on mutable message text
comment.body.includes('Your changes are now available')
If the wording ever changes, old "merged" comments won't be upgraded and new "available" comments won't be deduplicated. A more robust sentinel: add an invisible HTML comment at the top of the body, e.g. <!-- webex-release-bot-v1 -->, and match on that.
🔵 Nit — PR description placeholder not filled in
The description still contains < DESCRIBE YOUR CHANGES >. Please replace it with a brief explanation of what the workflow does (e.g., "Adds a comment-on-pr job that posts a release summary on the merged PR, listing updated package versions and a link to the changelog.").
Summary
| Severity | Issue |
|---|---|
| 🔴 High | Script injection via template literal in github-script |
| 🟡 Medium | Release tag URLs will 404 (no GitHub Releases created) |
| 🟡 Medium | Fragile bash pipe for package_versions output |
| 🟡 Medium | Fragile version extraction in publish-tag |
| 🟡 Medium | Unquoted expression expansion in run: steps |
| 🟢 Low | comment-on-pr runs even when nothing was published |
| 🟢 Low | Changelog stable_version stripping too broad |
| 🟢 Low | Comment deduplication relies on mutable message text |
| 🔵 Nit | PR description placeholder not filled in |