Conversation
|
Warning Review limit reached
More reviews will be available in 26 minutes. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughこのプルリクエストは、Discord ボットに RSS フィード監視機能を追加し、複数アプリケーション対応ビルドシステムを構築する変更を実装しています。新規 rss_cron アプリケーション、購読管理コマンド、データモデル更新、動的化された Docker・ビルドパイプラインを含みます。 ChangesRSS フィード監視機能
複数アプリケーション対応ビルド・デプロイシステム
Sequence Diagram(s)sequenceDiagram
participant Ready as Ready Handler
participant DB as Database
participant Repo as RSS Repo
participant Parser as gofeed
participant Discord as Discord API
participant Update as DB Update
Ready->>Repo: List RSS Settings
Repo->>DB: Query all settings
DB-->>Repo: Settings array
Repo-->>Ready: Settings array
loop Each RSS Setting
Ready->>Parser: ParseURL(url)
alt Parse Failed
Ready->>Update: IsFailed = true
Update->>DB: Update setting
else Parse Success
Parser-->>Ready: Feed data
Ready->>Ready: Sort items by PublishedParsed
Ready->>Ready: Collect target items by hash
loop Each target item
Ready->>Discord: CreateMessage(title, description, link)
Discord-->>Ready: Message created
end
Ready->>Ready: Compute new hash from first item
Ready->>Update: LastItemTitleDescriptionHash, IsFailed = false
Update->>DB: Update setting
end
end
🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/go.mod (2)
3-3:⚠️ Potential issue | 🟡 Minorgo.mod の
go 1.24.4は有効だが、Docker の Go バージョンと整合させてください
src/go.modのgo 1.24.4は公式に存在する有効なリリースです- ただし
Dockerfile.main/Dockerfile.rss_cronはgolang:1.26.4-alpine3.24を使用しているため、意図したターゲットランタイムに合わせてgo.modと統一(1.24.xに固定するか、1.26.xへ更新)してください🤖 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 `@src/go.mod` at line 3, Update the Go version to be consistent between src/go.mod and your Dockerfiles: change the module directive "go 1.24.4" in src/go.mod to match the Docker images (or update the Dockerfiles to match the module), e.g., set src/go.mod to "go 1.26.4" if you keep golang:1.26.4-alpine3.24 in Dockerfile.main and Dockerfile.rss_cron; ensure the version string in the go directive exactly matches the intended toolchain so builds inside Docker and local `go` behave identically.
20-46:⚠️ Potential issue | 🟠 Major間接依存(RSS側)の既知脆弱性が検出されました(更新必須)
golang.org/x/net v0.49.0(// indirect): GO-2026-5025/5027/5028/5029/5030(固定:v0.55.0)github.com/jackc/pgx/v5 v5.8.0(// indirect): GO-2026-4771/4772(固定:v5.9.0)- 標準ライブラリ(Go 1.26.3):
net/textproto/mime/crypto/x509(固定:go1.26.4。Goツールチェーン更新が必要)🤖 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 `@src/go.mod` around lines 20 - 46, The go.mod contains indirect dependencies with known vulnerabilities; update the versions and toolchain: bump golang.org/x/net from v0.49.0 to v0.55.0 and github.com/jackc/pgx/v5 from v5.8.0 to v5.9.0, and update the Go toolchain directive to go1.26.4 (or the project's Go version to 1.26.4) to pick up standard-library fixes; then run go get golang.org/x/net@v0.55.0 and go get github.com/jackc/pgx/v5@v5.9.0 (or edit go.mod and run go mod tidy) and re-run tests/build to ensure no breakage.
🧹 Nitpick comments (2)
Dockerfile.rss_cron (2)
20-22: ⚡ Quick winコンテナが root ユーザーで実行されます。
セキュリティのベストプラクティスとして、コンテナは非特権ユーザーで実行すべきです。現在のイメージは root ユーザーで実行されるため、コンテナが侵害された場合の影響範囲が広がります。
🛡️ 修正案: 非特権ユーザーを追加
FROM alpine:3.24.0 WORKDIR /root/ +RUN addgroup -g 1000 appuser && \ + adduser -D -u 1000 -G appuser appuser + RUN apk update && apk add --no-cache \ opus \ opus-dev \ opusfile \ opusfile-dev \ ffmpeg ENV PKG_CONFIG_PATH=/root/.local/lib/pkgconfig ENV LD_LIBRARY_PATH=/root/.local/lib/ COPY --from=builder /root/.local/ /root/.local/ RUN chmod -R 755 /root/.local +WORKDIR /home/appuser COPY --from=builder /app/src/main . -RUN chmod 755 ./main +RUN chown appuser:appuser ./main && chmod 755 ./main +USER appuser CMD ["/root/main"]注: CMD のパスも
/home/appuser/mainに変更する必要があります。🤖 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 `@Dockerfile.rss_cron` around lines 20 - 22, コンテナが root で実行されているので、Dockerfile のイメージ設定を非特権ユーザーで動くように修正してください: ベースの WORKDIR を /home/appuser に変更し、Dockerfile 内でユーザー appuser を作成(例: group/user 作成と HOME 設定)、該当ワークディレクトリとバイナリに対して所有権を chown し、最後に USER appuser を追加してコンテナを非 root で実行するようにし、合わせて CMD のパスを /home/appuser/main に更新してください(命名参照: WORKDIR, CMD, USER, appuser)。Source: Linters/SAST tools
35-36: 💤 Low value実行権限が過剰です。
chmod 777は書き込み権限を全ユーザーに付与しますが、実行ファイルには不要です。chmod 755で十分です。♻️ 修正案
-RUN chmod 777 ./main +RUN chmod 755 ./main🤖 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 `@Dockerfile.rss_cron` around lines 35 - 36, 実行バイナリの権限設定が過剰です:現在の RUN chmod 777 ./main(直後の COPY --from=builder /app/src/main . にある実行ファイル)を実行ファイルに必要な最小権限に下げるよう修正してください。具体的には chmod 777 を chmod 755 に変更して、所有者に書き込みを残しつつグループ/その他には実行・読み取りのみ与えるようにしてください。
🤖 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/docker-tag.yaml:
- Around line 28-45: The rss-cron image is built without passing the --rss-cron
flag to scripts/_build.sh, so Dockerfile.rss_cron ends up embedding the bot
binary; update Dockerfile.rss_cron to invoke ../scripts/_build.sh with the
--rss-cron argument (ensure the RUN line passes "--rss-cron"), and verify
scripts/_build.sh still recognizes that flag and sets TARGET appropriately (the
scripts/_build.sh entry handling --rss-cron and the Dockerfile.rss_cron RUN
invocation are the symbols to change).
In `@Dockerfile.main`:
- Line 19: The RUN instruction "RUN apk add build-base cmake ninja zip pkgconfig
perl nasm" leaves APK cache in the image; update that command to include the
--no-cache flag (i.e., "apk add --no-cache ...") so the package cache is not
stored in the layer, matching the existing pattern used earlier in the
Dockerfile.
- Line 33: Dockerfile のベースイメージ指定 "FROM alpine:3.24.0" は存在しないタグになっているため、実在する
Alpine のタグに置き換えてください(例: alpine:3.18 or alpine:latest); 変更後にローカル/CI 環境で docker
pull <タグ> または docker manifest inspect <タグ> を実行してタグが有効であることを確認し、Dockerfile の
"FROM alpine:3.24.0" 行をその有効なタグに更新してください。
- Line 3: Replace the non-existent base image tag "golang:1.26.4-alpine3.24" in
the Dockerfile's FROM instruction with a real, published tag (e.g.,
"golang:1.26.4-alpine" or another alpine variant confirmed via `docker manifest
inspect`); update the FROM line to use that verified tag so the builder stage
(FROM golang:1.26.4-alpine3.24) pulls successfully.
In `@Dockerfile.rss_cron`:
- Line 18: The Dockerfile currently invokes the build script without the target
flag, causing the default bot binary to be built; update the RUN invocation of
../scripts/_build.sh to pass the --rss-cron flag so the script builds the
rss_cron target (refer to the _build.sh script and the --rss-cron flag).
- Around line 30-33: Dockerfile の rss_cron イメージでビルダーステージに存在しない /root/.local
を参照している ENV PKG_CONFIG_PATH=/root/.local/lib/pkgconfig、ENV
LD_LIBRARY_PATH=/root/.local/lib/、COPY --from=builder /root/.local/
/root/.local/、RUN chmod -R 755 /root/.local
の各命令は不要なのでこれらの行を削除してビルド失敗や空ディレクトリのコピーを防いでください(rss_cron 用には /root/.local
を作成・利用していないため、該当する ENV/COPY/CHMOD 行を取り除くだけで問題ありません)。
- Around line 23-28: The Dockerfile's apk add includes audio packages (opus,
opus-dev, opusfile, opusfile-dev, ffmpeg) that are only needed by the Discord
voice code (voice/player.go) but not by rss_cron (rss_cron/main.go); remove
those packages from the RUN apk add line so the rss_cron image doesn't carry
unnecessary binaries and size/attack-surface. Locate the RUN apk update && apk
add --no-cache block and delete opus, opus-dev, opusfile, opusfile-dev and
ffmpeg from that list, then rebuild and verify rss_cron/main.go still builds
without audio deps.
In `@src/cmd/rss_cron/main.go`:
- Around line 111-146: The loop that builds targetItems incorrectly dereferences
rssSetting.LastItemTitleDescriptionHash and collects only the matching item; fix
by treating LastItemTitleDescriptionHash as nullable, iterating feed.Items from
newest to oldest and collecting each item into targetItems until you encounter a
computed hash equal to the saved hash (stop when matched) so that first-run (nil
saved hash) collects all items; keep using the existing hash computation
(base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", item.Title,
item.Description)))) and slices.Reverse(targetItems) so older-to-newer order is
preserved; after successfully sending messages via client.Rest.CreateMessage,
persist the newest item's hash into rssSetting.LastItemTitleDescriptionHash and
set rssSetting.IsFailed=false (and only mark failure on send error) so state
advances correctly.
- Around line 88-100: When fp.ParseURL(url) returns an error, you currently mark
rssSetting.IsFailed and call repo.Update(rssSetting) but then continue to use
feed (e.g., feed.Title and feed.Items) causing a panic; after successfully
updating the failed rssSetting you must skip further processing for that item
(i.e., continue the loop). Locate the ParseURL error branch around
fp.ParseURL(url), rssSetting.IsFailed and repo.Update and add a control flow
break (continue) after the update so no code references feed when parse failed.
In `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go`:
- Around line 80-95: responseEmbed の成功メッセージが TTS 用の文言になっているため、discord.Embed
を作成している箇所(変数 responseEmbed、discord.Embed の Title/Description フィールド)を修正して RSS
購読完了を正しく案内する文言に置き換えてください(例: Title を「RSS購読を開始しました」、Description
を「指定されたフィードの購読を開始しました」等)。CreateFollowupMessage /
discord.NewMessageCreate().WithEmbeds の呼び出しはそのまま使い、Footer や Timestamp は維持してください。
- Around line 70-78: The RSSSetting being saved lacks ChannelID and ignores DB
errors; update the logic around repository.NewGuildRepository/
guildRepo.GetOrCreate and repository.NewRSSSettingRepository/ rssRepo.Create to
(1) pass and persist the current channel ID into the model.RSSSetting.ChannelID
field, and (2) check and handle returned errors from GetOrCreate and Create (and
any DB ops via ctx.DB), ensuring that if any of these calls fail you do not
return a success response. Locate uses of GetOrCreate, Create, and the
RSSSetting struct to add ChannelID and propagate/handle errors appropriately so
cron code (snowflake.MustParse(rssSetting.ChannelID)) receives a valid saved
ChannelID.
In `@src/internal/bot/handlers/interaction/registry.go`:
- Around line 68-70: The "/rss" route currently only applies
DeferReplyMiddleware and has no execution handler, so the SlashCommand
registered in LoadRssCommandContext() never gets invoked; update the route
registration in registry.go to attach the actual handler by calling
rss.Subscribe(ctxData) (or the appropriate Subscribe handler function) inside
r.Route("/rss", ...) so the SlashCommand has an execution path while keeping
DeferReplyMiddleware applied.
---
Outside diff comments:
In `@src/go.mod`:
- Line 3: Update the Go version to be consistent between src/go.mod and your
Dockerfiles: change the module directive "go 1.24.4" in src/go.mod to match the
Docker images (or update the Dockerfiles to match the module), e.g., set
src/go.mod to "go 1.26.4" if you keep golang:1.26.4-alpine3.24 in
Dockerfile.main and Dockerfile.rss_cron; ensure the version string in the go
directive exactly matches the intended toolchain so builds inside Docker and
local `go` behave identically.
- Around line 20-46: The go.mod contains indirect dependencies with known
vulnerabilities; update the versions and toolchain: bump golang.org/x/net from
v0.49.0 to v0.55.0 and github.com/jackc/pgx/v5 from v5.8.0 to v5.9.0, and update
the Go toolchain directive to go1.26.4 (or the project's Go version to 1.26.4)
to pick up standard-library fixes; then run go get golang.org/x/net@v0.55.0 and
go get github.com/jackc/pgx/v5@v5.9.0 (or edit go.mod and run go mod tidy) and
re-run tests/build to ensure no breakage.
---
Nitpick comments:
In `@Dockerfile.rss_cron`:
- Around line 20-22: コンテナが root で実行されているので、Dockerfile
のイメージ設定を非特権ユーザーで動くように修正してください: ベースの WORKDIR を /home/appuser に変更し、Dockerfile
内でユーザー appuser を作成(例: group/user 作成と HOME 設定)、該当ワークディレクトリとバイナリに対して所有権を chown
し、最後に USER appuser を追加してコンテナを非 root で実行するようにし、合わせて CMD のパスを /home/appuser/main
に更新してください(命名参照: WORKDIR, CMD, USER, appuser)。
- Around line 35-36: 実行バイナリの権限設定が過剰です:現在の RUN chmod 777 ./main(直後の COPY
--from=builder /app/src/main . にある実行ファイル)を実行ファイルに必要な最小権限に下げるよう修正してください。具体的には
chmod 777 を chmod 755 に変更して、所有者に書き込みを残しつつグループ/その他には実行・読み取りのみ与えるようにしてください。
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 01912ca8-56f4-456a-89ed-411fffa004cc
⛔ Files ignored due to path filters (1)
src/go.sumis excluded by!**/*.sum
📒 Files selected for processing (11)
.github/workflows/docker-tag.yamlDockerfile.mainDockerfile.rss_cronscripts/_build.shsrc/cmd/rss_cron/main.gosrc/go.modsrc/internal/bot/handlers/interaction/command/general/rss.gosrc/internal/bot/handlers/interaction/command/general/rss/subscribe.gosrc/internal/bot/handlers/interaction/registry.gosrc/internal/model/rss_setting.gosrc/internal/repository/guild.go
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
…cribe.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/internal/bot/handlers/interaction/command/general/rss/subscribe.go (1)
126-146:⚠️ Potential issue | 🟠 Major | ⚡ Quick win成功レスポンスが公開メッセージになっており、購読 URL をチャンネルに漏らします。
このルートは
DeferReplyMiddleware(ctxData, true, false)でエフェメラル応答にしているのに、成功時だけWithEphemeral(false)を明示してURLフィールドも返しています。確認メッセージはエフェメラルに統一してください。PR objective では確認メッセージをエフェメラルで返す要件です。🤖 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 `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go` around lines 126 - 146, The success response is being sent as a public message and leaks the subscription URL; change the follow-up create call to send the embed ephemerally by replacing the explicit WithEphemeral(false) on the discord message builder used in the CreateFollowupMessage call with WithEphemeral(true) (or remove the explicit flag so it inherits DeferReplyMiddleware(ctxData, true, false)), keeping the responseEmbed (including the URL field) and the CreateFollowupMessage invocation unchanged otherwise so the confirmation remains ephemeral.
🤖 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 `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go`:
- Around line 97-108: feed.Items[0] will panic on empty feeds and the current
sort comparator mishandles nil PublishedParsed and stable ties; instead,
explicitly check for zero-length feed.Items and return/handle accordingly, then
perform a single-pass scan to pick the latest item (compare
PublishedParsed.UnixNano when both non-nil, treat nil as older, and fall back to
a deterministic tie-breaker like original index or non-empty Title/Description)
and compute the hash from that chosen item (the code around sort.Slice,
feed.Items, PublishedParsed, and the hash assignment should be updated).
- Around line 73-76: The code currently calls fp.ParseURL(url) and persists url
into RSSSetting without validation, enabling SSRF; before any network fetch or
persisting in Subscribe handler (and similarly in rss_cron paths referenced at
lines 116-121), validate the input: parse the URL and require scheme == "http"
or "https", resolve the host with net.LookupIP (or equivalent) and reject any
resolved IPs that are loopback, link-local, multicast or private
(RFC1918/AF_INET6 unique local) or unspecified; only after the URL passes that
whitelist may you call gofeed.NewParser().ParseURL(url) and save to RSSSetting;
apply the same validation function for rss_cron re-fetch to prevent saved
entries from causing SSRF later.
---
Outside diff comments:
In `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go`:
- Around line 126-146: The success response is being sent as a public message
and leaks the subscription URL; change the follow-up create call to send the
embed ephemerally by replacing the explicit WithEphemeral(false) on the discord
message builder used in the CreateFollowupMessage call with WithEphemeral(true)
(or remove the explicit flag so it inherits DeferReplyMiddleware(ctxData, true,
false)), keeping the responseEmbed (including the URL field) and the
CreateFollowupMessage invocation unchanged otherwise so the confirmation remains
ephemeral.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 75a73f9f-7dc6-4a21-9d2e-9cf3e92727e3
📒 Files selected for processing (5)
Dockerfile.mainDockerfile.rss_cronsrc/cmd/rss_cron/main.gosrc/internal/bot/handlers/interaction/command/general/rss/subscribe.gosrc/internal/bot/handlers/interaction/registry.go
🚧 Files skipped from review as they are similar to previous changes (2)
- Dockerfile.main
- src/cmd/rss_cron/main.go
Summary by CodeRabbit
リリースノート
New Features
Chores