Skip to content

[CI] Slack 알림 GitHub Actions 워크플로우 추가#179

Merged
inoray merged 3 commits intodevelopfrom
feature/slack-notifications
Apr 28, 2026
Merged

[CI] Slack 알림 GitHub Actions 워크플로우 추가#179
inoray merged 3 commits intodevelopfrom
feature/slack-notifications

Conversation

@yspaik
Copy link
Copy Markdown

@yspaik yspaik commented Apr 27, 2026

Summary

  • 이슈 생성, PR 생성, 댓글 멘션, 마일스톤 변경 4가지 이벤트를 #genos-지능형전처리기 Slack 채널로 알림
  • GenOS의 동일한 워크플로우 기반, ubuntu-latest runner로 조정
  • GENOS_MAP_JSON organization secret(All repositories) 재사용 — 별도 등록 불필요
  • 마일스톤 v2.1.0 05/07 운영망 배포 / v2.2.0 05/21 운영망 배포 (2주 단위) 동시 등록

추가된 파일

파일 트리거 비고
.github/workflows/issue_slack.yml issues: [opened] jq로 payload 생성
.github/workflows/pr_slack.yml pull_request: [opened] branch/status 포함
.github/workflows/mention-comment-notify.yml issue_comment: [created] GENOS_MAP_JSON으로 GitHub→Slack ID 매핑
.github/workflows/milestone-changed.yml issues/PR: [milestoned, demilestoned] v2.1.0·v2.2.0 대상
  • SLACK_WEBHOOK_URL repository secret 등록 — doc_parser → Settings → Secrets and variables → Actions (노출된 URL은 먼저 Slack App 페이지에서 Revoke 후 재발급)

검증 방법 (머지 후)

  1. 테스트 이슈 생성 → #genos-지능형전처리기에 알림 도달 확인
  2. 본인 GitHub ID로 멘션 댓글 → Slack 멘션 포함 확인
  3. 이슈에 v2.1.0 05/07 운영망 배포 마일스톤 부여 → 알림 확인

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Added automated Slack notifications for new issues, new pull requests, milestone assignments/removals, and @mentions in issue comments to improve team communication and workflow visibility.

이슈 생성·PR 생성·댓글 멘션·마일스톤 변경 이벤트를 #genos-지능형전처리기 채널로 알림.
GenOS 워크플로우 기반, ubuntu-latest runner, GENOS_MAP_JSON organization secret 재사용.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown

Note

Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

Warning

Rate limit exceeded

@yspaik has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 57 minutes and 31 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ddf002c2-e71d-43ee-b0d7-75deea729575

📥 Commits

Reviewing files that changed from the base of the PR and between 0dea6fc and 3f5d66a.

📒 Files selected for processing (1)
  • .github/workflows/mention-comment-notify.yml
📝 Walkthrough

Walkthrough

Four new GitHub Actions workflows were added to produce Slack notifications for newly opened PRs, newly created issues, new issue comments with mentions, and milestone assignments/removals; each workflow parses event payloads, converts timestamps to KST when applicable, builds Block Kit payloads, and posts via an incoming webhook.

Changes

Cohort / File(s) Summary
PR & Issue workflows
.github/workflows/pr_slack.yml, .github/workflows/issue_slack.yml
Add workflows triggered on PR/issue creation that convert created_at from UTC to KST (UTC+9), expose formatted timestamps as outputs, construct Slack Block Kit messages (title, number, author, avatar, link, times) and send via SLACK_WEBHOOK_URL.
Comment mention workflow
.github/workflows/mention-comment-notify.yml
Add workflow on issue_comment.created that filters bot comments, detects @<token> mentions (ignoring copilot), maps tokens to Slack IDs via GENOS_MAP_JSON, replaces mentions for Slack markup, and posts a Block Kit payload when non-copilot mentions exist.
Milestone workflow
.github/workflows/milestone-changed.yml
Add workflow on milestoned/demilestoned that checks milestone title allowlists, converts event time to KST, sets skip outputs for non-matching targets or fork-origin PRs (no secrets), and sends a Slack payload with repo/actor/milestone/timestamp when eligible.

Sequence Diagram(s)

sequenceDiagram
    participant GitHub as GitHub Events
    participant Actions as GitHub Actions Runner
    participant Processor as Event Processor (jq / python / github-script)
    participant Slack as Slack Incoming Webhook

    GitHub->>Actions: Emit event (PR/Issue/Comment/Milestone)
    Actions->>Processor: Provide event payload & env/secrets
    Processor->>Processor: Parse payload, convert timestamp to KST, detect mentions/milestone match
    Processor->>Processor: Build Slack Block Kit JSON
    Actions->>Slack: POST Block Kit JSON to SLACK_WEBHOOK_URL
    Slack->>Slack: Deliver message to channel
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 New workflows hop in one by one,
Timestamps shift to a bright KST sun,
Mentions mapped, milestones bell-rung,
Slack channels chirp with messages sung,
A rabbit's small dance — the notifications run! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding Slack notification GitHub Actions workflows for four event types.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/slack-notifications

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@yspaik yspaik requested a review from inoray April 27, 2026 11:02
@yspaik yspaik self-assigned this Apr 27, 2026
@yspaik yspaik added the enhancement New feature or request label Apr 27, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
.github/workflows/milestone-changed.yml (1)

9-13: TARGET_IN_MILESTONESTARGET_FROM_MILESTONES 중복 — 단일 변수로 통합 권장.

두 변수의 값이 동일하므로 운영 시 한쪽만 수정하다 불일치가 생길 위험이 있습니다. 별도로 분리할 의도가 없다면 하나로 합치거나 같은 변수를 재사용하세요.

 env:
   # ▼ 필요에 맞게 수정하세요 (쉼표로 여러 개 가능)
-  TARGET_IN_MILESTONES: "v2.1.0 05/07 운영망 배포, v2.2.0 05/21 운영망 배포"
-  TARGET_FROM_MILESTONES: "v2.1.0 05/07 운영망 배포, v2.2.0 05/21 운영망 배포"
+  TARGET_MILESTONES: "v2.1.0 05/07 운영망 배포, v2.2.0 05/21 운영망 배포"
   TIMEZONE_OFFSET_KST_HOURS: "9" # KST(+9)

(스크립트 내부에서도 inTargets/fromTargets를 동일 배열에서 파생시키면 됩니다.)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/milestone-changed.yml around lines 9 - 13, Replace the
duplicated env vars by introducing a single variable (e.g., TARGET_MILESTONES)
and remove TARGET_IN_MILESTONES and TARGET_FROM_MILESTONES; update any
workflow/script logic that currently reads TARGET_IN_MILESTONES or
TARGET_FROM_MILESTONES so that inTargets and fromTargets are both derived from
the single TARGET_MILESTONES (preserving existing parsing behavior), and keep
TIMEZONE_OFFSET_KST_HOURS unchanged; ensure all references to
TARGET_IN_MILESTONES and TARGET_FROM_MILESTONES are replaced with the new single
variable name throughout the workflow and associated scripts.
.github/workflows/mention-comment-notify.yml (1)

13-13: Upgrade actions/github-script to the latest stable version (v9).

actions/github-script@v6 is deprecated on GitHub Actions runners due to its Node 16 runtime. The latest stable version is v9.0.0, which uses Node 24. Upgrade to v9 instead of v7. The same issue applies to milestone-changed.yml in this PR.

Diff
-        uses: actions/github-script@v6
+        uses: actions/github-script@v9
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/mention-comment-notify.yml at line 13, Replace the
deprecated "uses: actions/github-script@v6" entry with "uses:
actions/github-script@v9" (or v9.0.0) to move the action to the Node 24 runtime;
update the same occurrences (the uses line) in this workflow and in
milestone-changed.yml so both workflows reference actions/github-script@v9, then
run CI to validate the workflows.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/issue_slack.yml:
- Around line 17-36: The convert_time_to_kr function currently manipulates
strings and fails to zero-pad hour/day and to roll over month/year when adding 9
hours; replace the manual logic in convert_time_to_kr with Python's datetime
parsing and timezone arithmetic (use datetime.fromisoformat or datetime.strptime
to parse created_time, apply timezone offset via timedelta or timezone objects,
then format with strftime '%Y-%m-%d %H:%M:%S' to guarantee zero-padding); update
the call sites (created_time, get_input, set_output) to use the new function
signature and mirror the same change in the duplicate function in pr_slack.yml
to keep behavior consistent.

In @.github/workflows/mention-comment-notify.yml:
- Around line 53-57: The current replacement loop only replaces the first
occurrence because transformed.replace(`@${ghId}`, `<@${userMap[ghId]}>`) is
used; change it to replace all occurrences by using transformed =
transformed.replaceAll(`@${ghId}`, `<@${userMap[ghId]}>`) or, if you prefer a
regex, construct an escaped pattern for ghId and call transformed =
transformed.replace(new RegExp(escapedGhIdPattern, 'g'), `<@${userMap[ghId]}>`)
so every mention of `@${ghId}` is substituted (ensure you escape special chars
when building the regex and reference the variables userMap, transformed, and
ghId).
- Line 33: Update the mentionRegex to match GitHub username rules: only
alphanumeric and hyphens allowed (no underscore), length 1–39, and cannot start
or end with a hyphen; implement this by replacing the current
/@([a-zA-Z0-9-_]+)/g with a pattern that captures an @ followed by a username
that begins with an alphanumeric, optionally has up to 37 alphanumeric or hyphen
chars, and (if longer than one char) ends with an alphanumeric so the total is
at most 39 and never starts/ends with '-'; update the mentionRegex constant
accordingly.

In @.github/workflows/milestone-changed.yml:
- Line 37: Update how msTitle is computed so it falls back to the webhook
payload milestone when obj?.milestone?.title is null: retrieve
obj?.milestone?.title first, then context.payload?.milestone?.title, and default
to empty string before trimming (i.e., change the expression used to set
msTitle), so the filter that relies on msTitle (used later where FROM
notifications are matched) will work for pull_request demilestoned events; note
that issues demilestoned cannot be recovered from the webhook payload and will
remain unsupported.

In @.github/workflows/pr_slack.yml:
- Around line 37-78: The Slack payload currently interpolates user-controlled
values directly in the "Send PR created message to Slack" step (id: slack) which
risks JSON breaking or injection; replace the inline interpolation of
github.event.pull_request.title, github.head_ref, github.base_ref,
github.event.pull_request.user.login, github.event.pull_request.user.avatar_url,
etc. with the safe jq -n --arg ... + env variable pattern used in
issue_slack.yml (build the JSON via jq from explicit --arg values instead of
embedding them), and update the KST conversion function (the current custom
datetime logic) to the datetime-based implementation from issue_slack.yml to fix
padding and month/year boundary bugs so timestamps are computed and formatted
consistently and safely.

---

Nitpick comments:
In @.github/workflows/mention-comment-notify.yml:
- Line 13: Replace the deprecated "uses: actions/github-script@v6" entry with
"uses: actions/github-script@v9" (or v9.0.0) to move the action to the Node 24
runtime; update the same occurrences (the uses line) in this workflow and in
milestone-changed.yml so both workflows reference actions/github-script@v9, then
run CI to validate the workflows.

In @.github/workflows/milestone-changed.yml:
- Around line 9-13: Replace the duplicated env vars by introducing a single
variable (e.g., TARGET_MILESTONES) and remove TARGET_IN_MILESTONES and
TARGET_FROM_MILESTONES; update any workflow/script logic that currently reads
TARGET_IN_MILESTONES or TARGET_FROM_MILESTONES so that inTargets and fromTargets
are both derived from the single TARGET_MILESTONES (preserving existing parsing
behavior), and keep TIMEZONE_OFFSET_KST_HOURS unchanged; ensure all references
to TARGET_IN_MILESTONES and TARGET_FROM_MILESTONES are replaced with the new
single variable name throughout the workflow and associated scripts.
🪄 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

Run ID: 47734bd8-0e75-409b-bee3-3e491f437369

📥 Commits

Reviewing files that changed from the base of the PR and between 2408017 and 9c06c2a.

📒 Files selected for processing (4)
  • .github/workflows/issue_slack.yml
  • .github/workflows/mention-comment-notify.yml
  • .github/workflows/milestone-changed.yml
  • .github/workflows/pr_slack.yml

Comment thread .github/workflows/issue_slack.yml Outdated
Comment thread .github/workflows/mention-comment-notify.yml Outdated
Comment thread .github/workflows/mention-comment-notify.yml
// fork에서 온 PR은 repo 시크릿 접근 불가 → 슬랙 전송 단계 스킵하도록 플래그 설정
const isForkPR = !isIssue && !!context.payload.pull_request?.head?.repo?.fork;

const msTitle = (obj?.milestone?.title || '').trim();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/milestone-changed.yml

Repository: genonai/doc_parser

Length of output: 6010


🌐 Web query:

GitHub webhook demilestoned event payload milestone field documentation

💡 Result:

The GitHub webhook for the "demilestoned" event is delivered as part of the "issues" or "pull_request" webhook events, with action: "demilestoned". It occurs when an issue or pull request is removed from a milestone. The payload structure includes standard fields like action, issue (or pull_request), repository, sender, etc. The "milestone" field is included in the "issue" object within the payload. This milestone object represents the milestone from which the issue was removed and contains details such as: - title: string (the title of the milestone) - id: integer - number: integer - state: string (open or closed) - description: string or null - creator: user object - open_issues: integer - closed_issues: integer - created_at: date-time - updated_at: date-time - due_on: date-time or null - closed_at: date-time or null - url, html_url, labels_url, node_id: strings After demilestoning, the issue.milestone may be set to null or retain the milestone data briefly in some implementations, but the event payload includes the milestone details of the removed one. This matches the structure for REST API issue events and timeline events for demilestoned actions, which webhooks mirror. Official documentation is at https://docs.github.com/en/webhooks/webhook-events-and-payloads#issues specifically for the demilestoned action under issues/pull_request events. Detailed schema from GitHub's API schemas confirms the milestone object presence.

Citations:


🌐 Web query:

GitHub demilestoned webhook payload structure issue.milestone null context.payload.milestone

💡 Result:

The GitHub "issues" webhook event with action "demilestoned" (and similarly for "pull_request") has the standard structure: {"action": "demilestoned", "issue": {...}, "repository": {...}, "sender": {...}, ...}. The context.payload.issue.milestone is null because removing an issue from a milestone sets the issue's milestone field to null at the time the webhook is triggered and sent. The payload reflects the updated state of the issue post-demilestoning. This matches the expected behavior per GitHub webhook design, where payloads capture the current state after the event action. For reference, in an "edited" example from official sources, milestone is shown as null. Other actions like "milestoned" would have the milestone populated in issue.milestone. A similar observation exists in Gitea (GitHub alternative), where demilestoned webhooks include the previous milestone data, but GitHub sets it to null. Official docs confirm "demilestoned" as a valid action for issues/pull_request events without special fields beyond the standard payload. Issue event types docs note a separate "milestone" object (with title) only in timeline/issue events APIs, not webhooks.

Citations:


🌐 Web query:

GitHub webhook demilestoned removed milestone data payload where

💡 Result:

The GitHub webhook payload for a "demilestoned" event (when an issue or pull request is removed from a milestone) is delivered as an "issues" or "pull_request" event with action "demilestoned". Key fields in the payload: - action: "demilestoned" - issue: Full issue object (for issues event) - pull_request: Full pull request object (for pull_request event; pull requests are issues) - repository: Repository object - sender: User who triggered the event - For pull_request demilestoned specifically: additional "milestone" object and "number" field. The milestone data for the removed milestone is included in the payload as a "milestone" object (with at least "title"). Example structure for pull_request demilestoned (from API schemas): { "action": "demilestoned", "milestone": { "title": "string", ... }, "number": integer, "pull_request": { ... }, "repository": { ... }, "sender": { ... } } For issues demilestoned: similar, with "issue" instead of "pull_request", no explicit top-level milestone but infer from context. Official docs confirm "demilestoned" as action in issues and pull_request webhooks. No full JSON example in search results, but schemas and event types match.

Citations:


demilestoned events cannot send FROM notifications — critical for both issues and pull requests.

When an issue or PR is removed from a milestone (demilestoned action), obj.milestone is set to null in the webhook payload (reflecting the post-action state). This causes msTitle at line 37 to become an empty string, making the filter at line 75 never match, so FROM notifications are never sent.

GitHub provides the removed milestone data differently depending on the event type:

  • Pull requests: context.payload.milestone.title is available
  • Issues: No top-level context.payload.milestone exists in the webhook payload

The proposed fix using context.payload.milestone as a fallback will work for pull request demilestoned events but will not fix issues demilestoned events — there is no data source available in the webhook for that case.

🛠️ Partial fix for pull requests
-            const msTitle = (obj?.milestone?.title || '').trim();
+            // For 'demilestoned': issue/PR.milestone is null post-action.
+            // GitHub provides removed milestone at context.payload.milestone (PR only).
+            const msTitle = (
+              context.payload.milestone?.title
+              || obj?.milestone?.title
+              || ''
+            ).trim();

This fix will restore FROM notifications for pull requests but not for issues. If issue demilestoned notifications are needed, a different approach may be required (such as querying the GitHub REST API for timeline events or accepting that issues demilestoned cannot be handled via webhooks alone).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const msTitle = (obj?.milestone?.title || '').trim();
// For 'demilestoned': issue/PR.milestone is null post-action.
// GitHub provides removed milestone at context.payload.milestone (PR only).
const msTitle = (
context.payload.milestone?.title
|| obj?.milestone?.title
|| ''
).trim();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/milestone-changed.yml at line 37, Update how msTitle is
computed so it falls back to the webhook payload milestone when
obj?.milestone?.title is null: retrieve obj?.milestone?.title first, then
context.payload?.milestone?.title, and default to empty string before trimming
(i.e., change the expression used to set msTitle), so the filter that relies on
msTitle (used later where FROM notifications are matched) will work for
pull_request demilestoned events; note that issues demilestoned cannot be
recovered from the webhook payload and will remain unsupported.

Comment on lines +37 to +78
- name: Send PR created message to Slack
id: slack
uses: slackapi/slack-github-action@v1.23.0
with:
payload: |
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*새로운 PR이 생성되었습니다* :fire: \n\n *${{ github.event.pull_request.title }}* #${{ github.event.pull_request.number }} \n branch: `${{ github.head_ref }}` >> `${{ github.base_ref }}` \n Link: <${{ github.event.pull_request.html_url }}> "
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Username:* \n ${{ github.event.pull_request.user.login }}"
},
{
"type": "mrkdwn",
"text": "*Created at:* \n ${{ steps.preprocess.outputs.time }}"
},
{
"type": "mrkdwn",
"text": "*Updated at:* \n ${{ github.event.pull_request.updated_at }}"
},
{
"type": "mrkdwn",
"text": "*Status:* \n ${{ github.event.pull_request.state }}"
}
],
"accessory": {
"type": "image",
"image_url": "${{ github.event.pull_request.user.avatar_url }}",
"alt_text": "profile_image"
}
}
]
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Slack 페이로드에 사용자 제어 입력(PR 제목/브랜치명)이 직접 보간 — 인젝션 위험.

${{ github.event.pull_request.title }}, ${{ github.head_ref }}, ${{ github.event.pull_request.user.login }}, ${{ github.event.pull_request.user.avatar_url }} 등은 모두 사용자(특히 fork 기여자)가 임의로 제어 가능한 값입니다. 이를 JSON 본문에 그대로 보간하면 따옴표·역슬래시·줄바꿈 등으로 페이로드 구조가 깨지거나, Slack 메시지에 임의 블록을 삽입하는 방식으로 악용될 수 있습니다. 같은 PR의 issue_slack.yml은 이미 jq -n --arg ... + env 변수 패턴으로 안전하게 처리하고 있으니, 동일 패턴으로 통일하는 것이 맞습니다.

또한 line 17-33의 KST 변환 함수는 issue_slack.yml과 동일한 버그(자릿수 패딩 누락 + 월/연 경계 미처리)를 가지고 있습니다. 해당 파일의 코멘트에서 제안한 datetime 기반 구현으로 함께 교체해 주세요.

🛠️ 제안 수정 (issue_slack.yml과 동일한 jq + env 패턴)
-      - name: Send PR created message to Slack
-        id: slack
-        uses: slackapi/slack-github-action@v1.23.0
-        with:
-          payload: |
-            {
-                "blocks": [
-                {
-                    "type": "section",
-                    "text": {
-                      "type": "mrkdwn",
-                      "text": "*새로운 PR이 생성되었습니다* :fire: \n\n *${{ github.event.pull_request.title }}* #${{ github.event.pull_request.number }} \n branch: `${{ github.head_ref }}` >> `${{ github.base_ref }}` \n Link: <${{ github.event.pull_request.html_url }}> "
-                    }
-                },
-                {
-                    "type": "section",
-                    "fields": [
-                      {
-                          "type": "mrkdwn",
-                          "text": "*Username:* \n ${{ github.event.pull_request.user.login }}"
-                      },
-                      {
-                          "type": "mrkdwn",
-                          "text": "*Created at:* \n ${{ steps.preprocess.outputs.time }}"
-                      },
-                      {
-                        "type": "mrkdwn",
-                        "text": "*Updated at:* \n ${{ github.event.pull_request.updated_at }}"
-                      },
-                      {
-                        "type": "mrkdwn",
-                        "text": "*Status:* \n ${{ github.event.pull_request.state }}"
-                      }
-                    ],
-                    "accessory": {
-                      "type": "image",
-                      "image_url": "${{ github.event.pull_request.user.avatar_url }}",
-                      "alt_text": "profile_image"
-                    }
-                }
-                ]
-            }
-        env:
-          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
-          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
+      - name: Create Slack payload
+        id: create_payload
+        run: |
+          jq -n \
+            --arg title  "$PR_TITLE" \
+            --arg number "$PR_NUMBER" \
+            --arg url    "$PR_URL" \
+            --arg head   "$PR_HEAD" \
+            --arg base   "$PR_BASE" \
+            --arg user   "$PR_USER" \
+            --arg avatar "$PR_AVATAR" \
+            --arg created "$CREATED_TIME" \
+            --arg updated "$UPDATED_TIME" \
+            --arg state  "$PR_STATE" \
+            '{
+              blocks: [
+                { type:"section", text:{ type:"mrkdwn",
+                  text: "*새로운 PR이 생성되었습니다* :fire: \n\n *\($title)* #\($number) \n branch: `\($head)` >> `\($base)` \n Link: <\($url)>" }},
+                { type:"section",
+                  fields: [
+                    { type:"mrkdwn", text:"*Username:* \n \($user)" },
+                    { type:"mrkdwn", text:"*Created at:* \n \($created)" },
+                    { type:"mrkdwn", text:"*Updated at:* \n \($updated)" },
+                    { type:"mrkdwn", text:"*Status:* \n \($state)" }
+                  ],
+                  accessory: { type:"image", image_url:$avatar, alt_text:"profile_image" }
+                }
+              ]
+            }' > payload.json
+        env:
+          PR_TITLE:    ${{ github.event.pull_request.title }}
+          PR_NUMBER:   ${{ github.event.pull_request.number }}
+          PR_URL:      ${{ github.event.pull_request.html_url }}
+          PR_HEAD:     ${{ github.head_ref }}
+          PR_BASE:     ${{ github.base_ref }}
+          PR_USER:     ${{ github.event.pull_request.user.login }}
+          PR_AVATAR:   ${{ github.event.pull_request.user.avatar_url }}
+          CREATED_TIME: ${{ steps.preprocess.outputs.time }}
+          UPDATED_TIME: ${{ github.event.pull_request.updated_at }}
+          PR_STATE:    ${{ github.event.pull_request.state }}
+      - name: Send PR created message to Slack
+        id: slack
+        uses: slackapi/slack-github-action@v1.23.0
+        with:
+          payload-file-path: "./payload.json"
+        env:
+          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
+          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/pr_slack.yml around lines 37 - 78, The Slack payload
currently interpolates user-controlled values directly in the "Send PR created
message to Slack" step (id: slack) which risks JSON breaking or injection;
replace the inline interpolation of github.event.pull_request.title,
github.head_ref, github.base_ref, github.event.pull_request.user.login,
github.event.pull_request.user.avatar_url, etc. with the safe jq -n --arg ... +
env variable pattern used in issue_slack.yml (build the JSON via jq from
explicit --arg values instead of embedding them), and update the KST conversion
function (the current custom datetime logic) to the datetime-based
implementation from issue_slack.yml to fix padding and month/year boundary bugs
so timestamps are computed and formatted consistently and safely.

yspaik and others added 2 commits April 28, 2026 09:40
날짜가 2자리수 되도록 수정

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: 백영상 <yspaik@gmail.com>
Github 사용자명 정규식 수정

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: 백영상 <yspaik@gmail.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/issue_slack.yml:
- Around line 16-24: The embedded Python block under the "script" step is
over-indented relative to its parent key causing YAML parse errors; fix by
dedenting the literal block so every line of the Python code is indented exactly
one level more than the "script: |" key. Adjust the indentation for the lines
that define kst, created_time, iso, dt_kst and the set_output call so they align
together under the script literal (ensuring the "script: |" line remains at its
current indentation and the Python lines are uniformly indented one level
inward).
🪄 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

Run ID: a34940f2-c4bf-49a9-9a74-a003e353ead7

📥 Commits

Reviewing files that changed from the base of the PR and between 9c06c2a and 0dea6fc.

📒 Files selected for processing (1)
  • .github/workflows/issue_slack.yml

Comment on lines +16 to +24
script: |
from datetime import datetime, timedelta, timezone
kst = timezone(timedelta(hours=9))
created_time = get_input("created_time")
# GitHub timestamps end with 'Z' (UTC); fromisoformat in 3.11+ accepts it,
# but normalize for older runtimes too.
iso = created_time.replace("Z", "+00:00")
dt_kst = datetime.fromisoformat(iso).astimezone(kst)
set_output("time", dt_kst.strftime("%Y-%m-%d %H:%M:%S"))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, find and examine the actual workflow file
fd -t f "issue_slack.yml" .github/workflows/

Repository: genonai/doc_parser

Length of output: 96


🏁 Script executed:

# Then read the file content with line numbers
cat -n .github/workflows/issue_slack.yml | head -50

Repository: genonai/doc_parser

Length of output: 2100


🏁 Script executed:

# Verify YAML syntax using available tools
python3 << 'EOF'
import yaml
try:
    with open('.github/workflows/issue_slack.yml', 'r') as f:
        yaml.safe_load(f)
    print("✓ YAML parsing successful")
except yaml.YAMLError as e:
    print("✗ YAML parsing failed:")
    print(e)
EOF

Repository: genonai/doc_parser

Length of output: 261


Fix the indentation in the embedded Python step.

The script: | body is not nested correctly—the Python code is indented with 8 spaces while the parent script key has 10 spaces. In YAML literal block scalars, content must be indented more than the parent key. This causes YAML parsing to fail at line 17, and the workflow will not run.

🛠️ Suggested fix
           script: |
-        from datetime import datetime, timedelta, timezone
-        kst = timezone(timedelta(hours=9))
-        created_time = get_input("created_time")
-        # GitHub timestamps end with 'Z' (UTC); fromisoformat in 3.11+ accepts it,
-        # but normalize for older runtimes too.
-        iso = created_time.replace("Z", "+00:00")
-        dt_kst = datetime.fromisoformat(iso).astimezone(kst)
-        set_output("time", dt_kst.strftime("%Y-%m-%d %H:%M:%S"))
+            from datetime import datetime, timedelta, timezone
+            kst = timezone(timedelta(hours=9))
+            created_time = get_input("created_time")
+            # GitHub timestamps end with 'Z' (UTC); fromisoformat in 3.11+ accepts it,
+            # but normalize for older runtimes too.
+            iso = created_time.replace("Z", "+00:00")
+            dt_kst = datetime.fromisoformat(iso).astimezone(kst)
+            set_output("time", dt_kst.strftime("%Y-%m-%d %H:%M:%S"))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
script: |
from datetime import datetime, timedelta, timezone
kst = timezone(timedelta(hours=9))
created_time = get_input("created_time")
# GitHub timestamps end with 'Z' (UTC); fromisoformat in 3.11+ accepts it,
# but normalize for older runtimes too.
iso = created_time.replace("Z", "+00:00")
dt_kst = datetime.fromisoformat(iso).astimezone(kst)
set_output("time", dt_kst.strftime("%Y-%m-%d %H:%M:%S"))
script: |
from datetime import datetime, timedelta, timezone
kst = timezone(timedelta(hours=9))
created_time = get_input("created_time")
# GitHub timestamps end with 'Z' (UTC); fromisoformat in 3.11+ accepts it,
# but normalize for older runtimes too.
iso = created_time.replace("Z", "+00:00")
dt_kst = datetime.fromisoformat(iso).astimezone(kst)
set_output("time", dt_kst.strftime("%Y-%m-%d %H:%M:%S"))
🧰 Tools
🪛 actionlint (1.7.12)

[error] 17-17: could not parse as YAML: could not find expected ':'

(syntax-check)

🪛 YAMLlint (1.38.0)

[error] 18-18: syntax error: could not find expected ':'

(syntax)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/issue_slack.yml around lines 16 - 24, The embedded Python
block under the "script" step is over-indented relative to its parent key
causing YAML parse errors; fix by dedenting the literal block so every line of
the Python code is indented exactly one level more than the "script: |" key.
Adjust the indentation for the lines that define kst, created_time, iso, dt_kst
and the set_output call so they align together under the script literal
(ensuring the "script: |" line remains at its current indentation and the Python
lines are uniformly indented one level inward).

@inoray inoray merged commit ca34a8b into develop Apr 28, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants