Skip to content

feat: add stale bot and release notification workflows#42

Open
abhizipstack wants to merge 2 commits intomainfrom
feat/stale-bot-and-release-notification
Open

feat: add stale bot and release notification workflows#42
abhizipstack wants to merge 2 commits intomainfrom
feat/stale-bot-and-release-notification

Conversation

@abhizipstack
Copy link
Copy Markdown
Contributor

What

  • Add stale bot workflow to auto-label and close inactive issues/PRs
  • Add release notification workflow to post to Slack on new releases

Why

  • Stale issues/PRs accumulate and clutter the backlog for community contributors
  • Team should be notified on Slack when a release is published

How

Stale bot (.github/workflows/stale.yml):

  • Runs daily at midnight UTC
  • Marks issues/PRs as stale after 60 days of inactivity
  • Auto-closes after 7 more days if no further activity
  • Exempts labels: pinned, security, bug
  • Uses existing stale label

Release notification (.github/workflows/release-notification.yml):

  • Triggers on GitHub release published event
  • Posts to Slack via incoming webhook
  • Requires SLACK_WEBHOOK_URL secret (skips gracefully if not configured)

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No — both are new workflows. Stale bot only affects issues/PRs with 60+ days of inactivity. Release notification only fires on release events.

Database Migrations

  • None

Env Config

  • SLACK_WEBHOOK_URL — needs to be added as repo secret for release notifications (optional, workflow skips if not set)

Notes on Testing

  • Stale bot: can be triggered manually via workflow_dispatch after merge
  • Release notification: will fire on next GitHub release (needs SLACK_WEBHOOK_URL secret)

Checklist

I have read and understood the Contribution Guidelines.

Stale bot:
- Runs daily, marks issues/PRs as stale after 60 days of inactivity
- Auto-closes after 7 more days if no activity
- Exempts pinned, security, and bug labels
- Uses existing 'stale' label (created in PR #15)

Release notification:
- Posts to Slack when a GitHub release is published
- Requires SLACK_WEBHOOK_URL secret (skips if not configured)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 6, 2026

Greptile Summary

This PR adds two new GitHub Actions workflows: a stale bot (stale.yml) and a release notification workflow (release-notification.yml). The stale bot is well-configured and ready to merge — previous review concerns (missing close-pr-message and inconsistent exempt-pr-labels) have been addressed. The release notification workflow introduces a P1 script injection risk that should be fixed before merging.

  • P1 – Script injection in release-notification.yml: github.event.release.tag_name and github.event.release.html_url are interpolated directly via ${{ }} inside a run: shell block, which is a documented GitHub Actions script-injection vector. The fix is to pass these values through env: variables instead.
  • P2 – Missing permissions: {} on the notify job: Without an explicit permissions block, GITHUB_TOKEN inherits repository defaults (potentially write access), even though the workflow never uses the token.
  • P2 – Mutable action version tags: Both actions/stale@v9 and slackapi/slack-github-action@v2.1.0 should be pinned to immutable commit SHAs to guard against supply-chain compromise."

Confidence Score: 4/5

Not safe to merge until the P1 script injection in release-notification.yml is fixed

Score of 4 reflects that stale.yml is ready but the release notification workflow has an active P1 security finding (script injection via direct ${{ }} interpolation in a run: block) that must be addressed before merging

.github/workflows/release-notification.yml — lines 15-17 (script injection) and missing permissions block

Important Files Changed

Filename Overview
.github/workflows/release-notification.yml New release-to-Slack notification workflow; has a P1 script injection issue on lines 15-17 and a missing permissions block
.github/workflows/stale.yml New stale-bot workflow; well-structured with correct permissions, all four message fields, and consistent exempt labels

Sequence Diagram

sequenceDiagram
    participant GH as GitHub
    participant WF as release-notification.yml
    participant Shell as run: step (bash)
    participant Action as slackapi/slack-github-action
    participant Slack as Slack Channel

    GH->>WF: release published event
    WF->>WF: check SLACK_WEBHOOK_URL secret != ''
    alt secret not configured
        WF-->>GH: job skipped
    else secret configured
        WF->>Shell: Build Slack message step
        Note over Shell: TAG/URL injected via ${{ }}<br/>NAME via toJSON+jq
        Shell-->>WF: steps.message.outputs.text
        WF->>Action: Post to Slack (webhook + payload)
        Action->>Slack: HTTP POST incoming webhook
        Slack-->>Action: 200 OK
    end
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: .github/workflows/release-notification.yml
Line: 15-17

Comment:
**Script injection via direct `${{ }}` interpolation in `run:` block**

`github.event.release.tag_name` (line 15) and `github.event.release.html_url` (line 17) are interpolated directly via `${{ }}` expressions inside a `run:` shell script. This is a known script-injection vector: if a tag name contains shell metacharacters (e.g. a backtick, `$(...)`, or a newline followed by fabricated `GITHUB_OUTPUT` content), the injected content will be executed as shell commands.

The safe pattern recommended by GitHub's security hardening guide is to pass event data through `env:` variables, which the shell treats as data rather than code:

```yaml
      - name: Build Slack message
        id: message
        env:
          TAG: ${{ github.event.release.tag_name }}
          RELEASE_NAME: ${{ github.event.release.name }}
          URL: ${{ github.event.release.html_url }}
        run: |
          NAME=$(echo "$RELEASE_NAME" | jq -Rs '.')
          echo "text=🚀 *Visitran ${TAG}* released! ${RELEASE_NAME} <${URL}|View Release Notes>" >> "$GITHUB_OUTPUT"
```

This ensures no user-controlled string is ever interpolated directly into the shell command.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: .github/workflows/release-notification.yml
Line: 7-10

Comment:
**Missing `permissions` block — GITHUB_TOKEN has unnecessary default scope**

The workflow has no `permissions` key. Without it, the job inherits the repository's default token permissions, which may include write access to `contents`, `pull-requests`, etc. Since this workflow only posts to Slack via a webhook secret and never touches `GITHUB_TOKEN`, adding an explicit `permissions: {}` block follows the principle of least privilege.

Note that `stale.yml` correctly declares only the two permissions it needs — this workflow should follow the same discipline:

```suggestion
jobs:
  notify:
    runs-on: ubuntu-latest
    permissions: {}
    if: ${{ secrets.SLACK_WEBHOOK_URL != '' }}
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: .github/workflows/stale.yml
Line: 16

Comment:
**Mutable action version tags — pin to commit SHAs for supply-chain safety**

Both workflows reference actions by mutable version tags (`actions/stale@v9` here, `slackapi/slack-github-action@v2.1.0` in `release-notification.yml`). A tag can be silently moved to a different commit by the action maintainer (or a compromised account), causing malicious code to run in your workflows without any change to this repository.

The recommended practice is to pin to a full-length immutable commit SHA, with the version tag as a comment:

```suggestion
      - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9
```

The same applies to `slackapi/slack-github-action@v2.1.0` in `release-notification.yml` — verify the current SHA from the upstream release page before pinning.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix: address Greptile review — JSON inje..." | Re-trigger Greptile

@abhizipstack abhizipstack self-assigned this Apr 6, 2026
…pt labels

- Fix JSON injection in Slack payload — build message in run step
  to avoid malformed JSON from release names with quotes
- Add close-pr-message for stale PRs — contributors get context
- Add bug to exempt-pr-labels — match issue exemptions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment on lines +15 to +17
TAG="${{ github.event.release.tag_name }}"
NAME=$(echo '${{ toJSON(github.event.release.name) }}' | jq -r '.')
URL="${{ github.event.release.html_url }}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Script injection via direct ${{ }} interpolation in run: block

github.event.release.tag_name (line 15) and github.event.release.html_url (line 17) are interpolated directly via ${{ }} expressions inside a run: shell script. This is a known script-injection vector: if a tag name contains shell metacharacters (e.g. a backtick, $(...), or a newline followed by fabricated GITHUB_OUTPUT content), the injected content will be executed as shell commands.

The safe pattern recommended by GitHub's security hardening guide is to pass event data through env: variables, which the shell treats as data rather than code:

      - name: Build Slack message
        id: message
        env:
          TAG: ${{ github.event.release.tag_name }}
          RELEASE_NAME: ${{ github.event.release.name }}
          URL: ${{ github.event.release.html_url }}
        run: |
          NAME=$(echo "$RELEASE_NAME" | jq -Rs '.')
          echo "text=🚀 *Visitran ${TAG}* released! ${RELEASE_NAME} <${URL}|View Release Notes>" >> "$GITHUB_OUTPUT"

This ensures no user-controlled string is ever interpolated directly into the shell command.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/release-notification.yml
Line: 15-17

Comment:
**Script injection via direct `${{ }}` interpolation in `run:` block**

`github.event.release.tag_name` (line 15) and `github.event.release.html_url` (line 17) are interpolated directly via `${{ }}` expressions inside a `run:` shell script. This is a known script-injection vector: if a tag name contains shell metacharacters (e.g. a backtick, `$(...)`, or a newline followed by fabricated `GITHUB_OUTPUT` content), the injected content will be executed as shell commands.

The safe pattern recommended by GitHub's security hardening guide is to pass event data through `env:` variables, which the shell treats as data rather than code:

```yaml
      - name: Build Slack message
        id: message
        env:
          TAG: ${{ github.event.release.tag_name }}
          RELEASE_NAME: ${{ github.event.release.name }}
          URL: ${{ github.event.release.html_url }}
        run: |
          NAME=$(echo "$RELEASE_NAME" | jq -Rs '.')
          echo "text=🚀 *Visitran ${TAG}* released! ${RELEASE_NAME} <${URL}|View Release Notes>" >> "$GITHUB_OUTPUT"
```

This ensures no user-controlled string is ever interpolated directly into the shell command.

How can I resolve this? If you propose a fix, please make it concise.

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