chore: harden qa-create skill workflow and apply lint --fix#1630
Conversation
|
Warning Rate limit exceeded
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 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 configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR makes two independent updates: a documentation enhancement to the QA test creation procedure requiring mandatory DOM verification via MCP Playwright before selector code generation, and a removal of an eslint-disable lint suppression comment from the media handler. ChangesTest Generation Procedure Enhancement
Lint Suppression Cleanup
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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. Review rate limit: 0/1 reviews remaining, refill in 52 minutes and 12 seconds.Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.claude/skills/qa-create/SKILL.md (1)
4-4:⚠️ Potential issue | 🟠 MajorStep 3.5 requires MCP Playwright verification but lacks tool allowance and invocation guidance.
Line 39–47 mandates DOM verification with "MCP Playwright," yet
allowed-toolsat line 4 omits all Playwright tools (compare:release-xpostandreleaseexplicitly listmcp__electron-playwright__*tools). Step 3.5 does not document how to invoke Playwright if tools are unavailable—whether viaTaskdelegating to themcp-pwskill or another mechanism. This creates ambiguity: developers cannot directly use Playwright tools, and the workflow path is undocumented.Either add Playwright tools to
allowed-tools, or clarify in Step 3.5 that verification occurs viaTaskinvocation of themcp-pwskill.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.claude/skills/qa-create/SKILL.md at line 4, The README/skill config omits Playwright tools needed by Step 3.5: update the allowed-tools list or document the alternative; specifically either add the mcp__electron-playwright__* entries to the allowed-tools declaration so MCP Playwright can be invoked directly, or update Step 3.5 to explicitly state that DOM verification is performed by delegating a Task to the mcp-pw skill (showing the Task invocation pattern and expected inputs/outputs). Modify the allowed-tools symbol or the Step 3.5 text accordingly so callers know whether to call MCP Playwright directly (via mcp__electron-playwright__*) or via a Task to mcp-pw.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/mulmo/handler_media.ts`:
- Around line 74-76: The current code constructs AdmZip with zipFilePath and
calls zip.extractAllTo(extractDir, true) which allows Zip Slip path traversal;
replace this with manual per-entry validation: iterate zip.getEntries(), for
each entry compute the destination path by joining extractDir and
entry.entryName and resolving it (using path.resolve), then ensure the resolved
path startsWith the resolved extractDir; if it does not, skip or throw an error
and log the offending entry; only after validation create parent dirs and write
the entry data (or call entry.extract to the validated path) so no archive entry
can escape extractDir.
---
Outside diff comments:
In @.claude/skills/qa-create/SKILL.md:
- Line 4: The README/skill config omits Playwright tools needed by Step 3.5:
update the allowed-tools list or document the alternative; specifically either
add the mcp__electron-playwright__* entries to the allowed-tools declaration so
MCP Playwright can be invoked directly, or update Step 3.5 to explicitly state
that DOM verification is performed by delegating a Task to the mcp-pw skill
(showing the Task invocation pattern and expected inputs/outputs). Modify the
allowed-tools symbol or the Step 3.5 text accordingly so callers know whether to
call MCP Playwright directly (via mcp__electron-playwright__*) or via a Task to
mcp-pw.
🪄 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: 89ccdff6-7ba5-4b39-b69c-78755bb6be2f
📒 Files selected for processing (2)
.claude/skills/qa-create/SKILL.mdsrc/main/mulmo/handler_media.ts
| const zip = new AdmZip(zipFilePath); | ||
| // eslint-disable-next-line sonarjs/no-unsafe-unzip | ||
|
|
||
| zip.extractAllTo(extractDir, true); |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
For adm-zip v0.5.17, does extractAllTo itself prevent Zip Slip/path traversal, and what secure extraction pattern is recommended for untrusted zip files?
💡 Result:
No. For adm-zip v0.5.17, extractAllTo does not provide reliable path-traversal/Zip Slip protection by itself for untrusted ZIPs; issues in adm-zip’s extraction logic show entries can be used to write outside the intended target directory. Grounded evidence: (1) A 2017 issue report states extractAllTo/extractEntryTo do not sanitize zip entry filenames and can extract outside targetPath because they combine targetPath and entryName without checking/sanitizing the resolved path; it recommends verifying the resolved path is under targetPath. (2) GitHub Security Lab’s advisory GHSL-2020-198 describes extractAllTo as attempting to ensure files are not extracted outside the target folder, but the enforcement contains a loophole that can result in extraction into a sibling folder (cross-folder extraction), which can enable overwriting files outside the intended destination. (3) Additional fix discussions/PRs in the adm-zip repo show the project had to add explicit checks/sanitization to prevent archived files being extracted outside the target path. Recommended secure extraction pattern for untrusted ZIPs: - Do not rely on extractAllTo/extractEntryTo as the sole mitigation. - Instead, for each ZIP entry, compute the final extraction path (using path resolution/normalization) and accept the entry only if the computed path is strictly within the intended destination directory (i.e., destination must be a real prefix after resolving both to absolute/canonical paths). Reject otherwise. - Create/operate inside a dedicated “quarantine” directory that is empty and not attacker-controlled, and avoid symlink-related issues by ensuring the destination directory is writable only by the app and not under attacker control. Concrete pattern (Node.js sketch): 1) const path = require('path'); 2) const root = path.resolve(destDir); 3) For each entryName from the archive: - const normalized = entryName.replace(/\/g,'/'); // normalize separators - const target = path.resolve(root, normalized); - if (!target.startsWith(root + path.sep)) reject/skip the entry. - Only then extract/write that entry to target. This “validate resolved path stays under root” approach matches the mitigation guidance described in both the adm-zip maintainer discussions/PRs and general Zip Slip guidance (including verifying child-of destination after resolving paths).
Citations:
- 1: Adm-zip extractAllTo and extractEntryTo path traversal cthackers/adm-zip#176
- 2: https://securitylab.github.com/advisories/GHSL-2020-198-zipslip-adm-zip/
- 3: fix: prevent extracting archived files outside of target path cthackers/adm-zip#212
- 4: https://developer.android.com/privacy-and-security/risks/zip-path-traversal
🏁 Script executed:
# Check adm-zip version in dependencies
rg '"adm-zip"' --type jsonRepository: receptron/mulmocast-app
Length of output: 106
🏁 Script executed:
# Read the actual code at the flagged lines with surrounding context
cat -n src/main/mulmo/handler_media.ts | sed -n '60,100p'Repository: receptron/mulmocast-app
Length of output: 1498
🏁 Script executed:
# Check if there's any path validation helper or utility used elsewhere in the file
rg 'extractAllTo|normalize|resolve.*extract' src/main/mulmo/handler_media.ts -A 3 -B 3Repository: receptron/mulmocast-app
Length of output: 264
Implement Zip Slip validation for untrusted archive extraction
Line 76 extracts all entries without validating resolved paths. adm-zip v0.5.17 does not prevent path traversal; a malicious archive can extract files outside extractDir. This is documented in GitHub Security Lab advisory GHSL-2020-198 and confirmed in adm-zip issues #176 and #212.
Validate each entry's resolved path before extraction:
Suggested fix
// zipファイルを展開
const zip = new AdmZip(zipFilePath);
+ const extractRoot = path.resolve(extractDir) + path.sep;
+ for (const entry of zip.getEntries()) {
+ const outputPath = path.resolve(extractDir, entry.entryName);
+ if (!outputPath.startsWith(extractRoot)) {
+ throw new Error(`Unsafe zip entry path: ${entry.entryName}`);
+ }
+ }
zip.extractAllTo(extractDir, true);📝 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.
| const zip = new AdmZip(zipFilePath); | |
| // eslint-disable-next-line sonarjs/no-unsafe-unzip | |
| zip.extractAllTo(extractDir, true); | |
| const zip = new AdmZip(zipFilePath); | |
| const extractRoot = path.resolve(extractDir) + path.sep; | |
| for (const entry of zip.getEntries()) { | |
| const outputPath = path.resolve(extractDir, entry.entryName); | |
| if (!outputPath.startsWith(extractRoot)) { | |
| throw new Error(`Unsafe zip entry path: ${entry.entryName}`); | |
| } | |
| } | |
| zip.extractAllTo(extractDir, true); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main/mulmo/handler_media.ts` around lines 74 - 76, The current code
constructs AdmZip with zipFilePath and calls zip.extractAllTo(extractDir, true)
which allows Zip Slip path traversal; replace this with manual per-entry
validation: iterate zip.getEntries(), for each entry compute the destination
path by joining extractDir and entry.entryName and resolving it (using
path.resolve), then ensure the resolved path startsWith the resolved extractDir;
if it does not, skip or throw an error and log the offending entry; only after
validation create parent dirs and write the entry data (or call entry.extract to
the validated path) so no archive entry can escape extractDir.
Summary
Why
Scope
Verification
Summary by CodeRabbit
Documentation
Chores