Conversation
- 新しいデータ構造を追加 (ParsedDocument, RenderedPage, OutputFile) - 純粋関数でデータ変換を行うように変更 - 副作用(ファイル I/O)を Phase 2 に分離 - 不要になった関数を削除 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary of ChangesHello @zztkm, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! このプルリクエストは、静的サイトジェネレータの Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces an excellent refactoring of the build command to a functional pipeline architecture, significantly improving code clarity and maintainability by separating pure transformations and file I/O. However, a high-severity path traversal vulnerability was identified in the tag page generation logic. Unsanitized tag names from markdown files are used to construct output file paths, which could allow a malicious markdown file to overwrite arbitrary files on the system where the build is performed. It is recommended to sanitize tag names to ensure they only contain safe characters before using them in file paths. Additionally, the review highlighted suggestions to keep phase 1 functions more strictly pure and improvements to reduce unnecessary data clones for better performance.
| let tag_path_str = config.build.tags.url_pattern.replace("{tag}", &tag_name); | ||
| let relative_path = tag_path_str.trim_start_matches('/'); | ||
|
|
||
| let path = if relative_path.ends_with('/') { | ||
| Path::new(&config.dist) | ||
| .join(relative_path) | ||
| .join("index.html") | ||
| } else { | ||
| Path::new(&config.dist).join(relative_path) | ||
| }; |
There was a problem hiding this comment.
The tag_name from markdown frontmatter is used to construct the output file path without sanitization. A malicious tag name like ../../evil can lead to a path traversal vulnerability, allowing arbitrary files to be written outside the dist directory during the build process. This is particularly dangerous if the tool is used to build sites from untrusted repositories.
| let tag_path_str = config.build.tags.url_pattern.replace("{tag}", &tag_name); | |
| let relative_path = tag_path_str.trim_start_matches('/'); | |
| let path = if relative_path.ends_with('/') { | |
| Path::new(&config.dist) | |
| .join(relative_path) | |
| .join("index.html") | |
| } else { | |
| Path::new(&config.dist).join(relative_path) | |
| }; | |
| let sanitized_tag = tag_name.replace(|c: char| !c.is_alphanumeric() && c != '-' && c != '_', "_"); | |
| let tag_path_str = config.build.tags.url_pattern.replace("{tag}", &sanitized_tag); | |
| let relative_path = tag_path_str.trim_start_matches('/'); | |
| let path = if relative_path.ends_with('/') { | |
| Path::new(&config.dist) | |
| .join(relative_path) | |
| .join("index.html") | |
| } else { | |
| Path::new(&config.dist).join(relative_path) | |
| }; |
| fs::write(&output_path, rendered) | ||
| .with_context(|| format!("Failed to write output file: {}", output_path.display()))?; | ||
|
|
||
| println!("Generated: {}", output_path.display()); |
| Path::new(&config.dist).join(relative_path) | ||
| }; | ||
|
|
||
| println!("Generated tag page: {}", path.display()); |
| write_all_outputs( | ||
| rendered_pages.iter().map(|p| OutputFile { | ||
| path: p.output_path.clone(), | ||
| content: p.html.clone(), | ||
| }), | ||
| )?; |
There was a problem hiding this comment.
ここで rendered_pages は .iter() で参照としてイテレートされ、各要素のフィールドがクローンされています。しかし、この処理の後 rendered_pages は使われていないため、.into_iter() を使って所有権をムーブすることで、path と content のクローンを避けることができます。
| write_all_outputs( | |
| rendered_pages.iter().map(|p| OutputFile { | |
| path: p.output_path.clone(), | |
| content: p.html.clone(), | |
| }), | |
| )?; | |
| write_all_outputs( | |
| rendered_pages.into_iter().map(|p| OutputFile { | |
| path: p.output_path, | |
| content: p.html, | |
| }), | |
| )?; |
Summary
buildコマンドの内部実装を関数型パイプラインアーキテクチャにリファクタリング新しいデータ構造
ParsedDocument- パース済み Markdown(frontmatter と HTML コンテンツを保持)RenderedPage- レンダリング済みページ(出力パス、HTML、メタデータを保持)OutputFile- 出力ファイル(パスとコンテンツを保持)パイプライン構成
Test plan
cargo buildでコンパイル確認cargo testでテスト実行example_siteでvss buildを実行し、生成結果を確認siteでvss buildを実行し、生成結果を確認🤖 Generated with Claude Code