Skip to content

feat(coverage): validate that file paths are within repository boundary#2550

Draft
brynary wants to merge 3 commits intomainfrom
feat/coverage-validate-workspace-containment
Draft

feat(coverage): validate that file paths are within repository boundary#2550
brynary wants to merge 3 commits intomainfrom
feat/coverage-validate-workspace-containment

Conversation

@brynary
Copy link
Member

@brynary brynary commented Dec 2, 2025

Summary

  • Add workspace containment validation to coverage uploads
  • Files that exist on disk but are outside the repository are now tracked separately as "outside workspace"
  • Such files count as "not present" for validation threshold calculation
  • CLI displays outside-workspace files when present (non-empty)
  • Validation failure message includes them when count is non-zero

Changes

  • qlty-coverage/src/publish/plan.rs - Added workspace_root: Option<PathBuf> field
  • qlty-coverage/src/publish/planner.rs - Updated new() to accept workspace_root, pass it to Plan
  • qlty-coverage/src/publish/report.rs - Added outside_workspace_files: HashSet<String> field
  • qlty-coverage/src/publish/processor.rs - Added is_within_workspace() check, populates outside_workspace_files
  • qlty-coverage/src/validate.rs - Added workspace_root to Validator, files_outside_workspace to ValidationResult, containment check
  • qlty-cli/src/commands/coverage/publish.rs - Gets workspace root, passes to Planner/Validator, displays outside-workspace files

Test plan

  • Added 4 new unit tests for outside-workspace detection in validate.rs
  • All 201 tests in qlty-coverage pass
  • cargo check passes
  • qlty fmt and qlty check --level=low --fix pass with no issues

🤖 Generated with Claude Code

Add workspace containment validation to coverage uploads. Previously, a
path like `../../../foo/bar.sh` that existed on disk but was outside the
repository would pass validation. Now such files are detected and tracked
separately as "outside workspace" files.

Changes:
- Add workspace_root field to Plan and pass through from Planner
- Add outside_workspace_files tracking to Report and Processor
- Add is_within_workspace() check in Processor to categorize files
- Update Validator to track files_outside_workspace in ValidationResult
- Update CLI to display outside-workspace files when present
- Files outside workspace count as "not present" for validation threshold

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings December 2, 2025 03:05
@github-actions
Copy link
Contributor

github-actions bot commented Dec 2, 2025

No issue mentions found. Please mention an issue in the pull request description.

Use GitHub automation to close the issue when a PR is merged

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds workspace boundary validation to coverage uploads to prevent files outside the repository from being counted towards coverage validation thresholds.

  • Files existing outside the repository workspace are now tracked separately as "outside workspace"
  • The validation threshold calculation excludes these files (treating them similarly to missing files)
  • CLI provides clear feedback about files outside the workspace when present

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
qlty-coverage/src/validate.rs Added workspace containment check in validator with is_within_workspace() method and new field files_outside_workspace in ValidationResult
qlty-coverage/src/publish/processor.rs Added workspace boundary checking during file processing with is_within_workspace() method to populate outside_workspace_files
qlty-coverage/src/publish/report.rs Added outside_workspace_files field to track files outside workspace
qlty-coverage/src/publish/planner.rs Updated to accept and pass workspace_root parameter through to Plan
qlty-coverage/src/publish/plan.rs Added workspace_root field to store workspace boundary
qlty-cli/src/commands/coverage/publish.rs Updated to obtain workspace root, display outside-workspace files, and include them in validation error messages

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +78 to +87
fn is_within_workspace(&self, file_path: &Path) -> bool {
let Some(ref workspace_root) = self.workspace_root else {
return true;
};

match (file_path.canonicalize(), workspace_root.canonicalize()) {
(Ok(canonical_file), Ok(canonical_root)) => canonical_file.starts_with(&canonical_root),
_ => false,
}
}
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

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

The is_within_workspace method is duplicated identically in processor.rs (lines 95-104). Consider extracting this logic into a shared utility function to maintain DRY (Don't Repeat Yourself) principle and ensure consistent behavior across the codebase.

Copilot uses AI. Check for mistakes.
Comment on lines +95 to +104
fn is_within_workspace(&self, file_path: &Path) -> bool {
let Some(ref workspace_root) = self.plan.workspace_root else {
return true;
};

match (file_path.canonicalize(), workspace_root.canonicalize()) {
(Ok(canonical_file), Ok(canonical_root)) => canonical_file.starts_with(&canonical_root),
_ => false,
}
}
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

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

The is_within_workspace method is duplicated identically in validate.rs (lines 78-87). Consider extracting this logic into a shared utility function to maintain DRY (Don't Repeat Yourself) principle and ensure consistent behavior across the codebase.

Copilot uses AI. Check for mistakes.
@qltysh
Copy link
Contributor

qltysh bot commented Dec 2, 2025

1 new issue

Tool Category Rule Count
qlty Structure Function with high complexity (count = 20): compute 1

…update snapshot

- Fix pluralization: "1 file" vs "X files" for both missing and outside repository counts
- Update publish_validate.stderr snapshot to include the new detail line

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@qltysh
Copy link
Contributor

qltysh bot commented Dec 2, 2025

Diff Coverage for ubuntu-latest: The code coverage on the diff in this pull request is 73.9%.

Total Coverage for ubuntu-latest: This PR will decrease coverage by 0.05%.

File Coverage Changes
Path File Coverage Δ Indirect
qlty-cli/src/commands/coverage/publish.rs -7.7
qlty-config/src/library.rs 0.5
qlty-coverage/src/ci/github.rs -0.3
qlty-coverage/src/publish/planner.rs 0.1
qlty-coverage/src/publish/processor.rs -4.1
qlty-coverage/src/utils.rs -1.7
🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@qltysh
Copy link
Contributor

qltysh bot commented Dec 2, 2025

Diff Coverage for macos-15: The code coverage on the diff in this pull request is 73.9%.

Total Coverage for macos-15: This PR will decrease coverage by 0.05%.

File Coverage Changes
Path File Coverage Δ Indirect
qlty-cli/src/commands/coverage/publish.rs -7.7
qlty-config/src/library.rs 0.5
qlty-coverage/src/ci/github.rs -0.3
qlty-coverage/src/publish/planner.rs 0.1
qlty-coverage/src/publish/processor.rs -4.1
qlty-coverage/src/utils.rs -1.7
🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

Copilot AI review requested due to automatic review settings December 2, 2025 14:21
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings December 2, 2025 14:45
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Add is_path_within_workspace function to utils.rs
- Remove wrapper methods and call utility directly from validate.rs and processor.rs
- Clean up unused Path imports

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@brynary brynary force-pushed the feat/coverage-validate-workspace-containment branch from 691a925 to 020ddd0 Compare December 2, 2025 15:08
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.

2 participants