Skip to content

[rust-guard] Rust Guard: list_commits Vec clone + project-item test coverage #6940

Closed

Description

@github-actions

🦀 Rust Guard Improvement Report

Improvement 1: Eliminate Redundant Vec<String> Clone in list_commits Arm

Category: Performance
File(s): guards/github-guard/rust-guard/src/labels/response_paths.rs
Effort: Small (< 15 min)
Risk: Low

Problem

In the list_commits arm of label_response_paths (around line 341–354), default_secrecy is created as a Vec<String>, immediately cloned to produce default_secrecy_shared: SharedLabels, and then the original is moved into default_labels. This wastes one full Vec<String> deep-clone (N string copies, one new backing buffer) on every list_commits call, even though the three other recently-fixed arms (list_pull_requests, list_issues, list_releases) already use the correct pattern.

// CURRENT — wasteful
let default_secrecy =
    repo_visibility_secrecy(&arg_owner, &arg_repo, &default_repo, ctx);
// ...
let default_secrecy_shared: crate::SharedLabels = default_secrecy.clone().into();  // ← Vec clone here
// ...
return Some(PathLabelResult {
    ...
    default_labels: Some(crate::ResourceLabels {
        secrecy: default_secrecy.into(),   // ← original moved here
        ...
    }),
    ...
});

Suggested Change

Convert to SharedLabels immediately, then clone the Arc (O(1)) wherever needed:

Before

let default_secrecy =
    repo_visibility_secrecy(&arg_owner, &arg_repo, &default_repo, ctx);
// ...further down...
let default_secrecy_shared: crate::SharedLabels = default_secrecy.clone().into();
// ...in per-item loop...
secrecy: default_secrecy_shared.clone(),
// ...in default_labels...
secrecy: default_secrecy.into(),

After

let default_secrecy: crate::SharedLabels =
    repo_visibility_secrecy(&arg_owner, &arg_repo, &default_repo, ctx).into();
// ...further down, no separate `clone().into()` needed...
// ...in per-item loop...
secrecy: default_secrecy.clone(),
// ...in default_labels...
secrecy: default_secrecy,   // move (last use)

Why This Matters

SharedLabels wraps Arc<Vec<String>>, so every .clone() on it is a single atomic refcount increment — O(1), zero allocations. The current Vec::clone() allocates a new buffer and copies every string. For a typical list_commits response with private-repo secrecy labels (1–2 strings), this is minor, but the same pattern was already corrected in every other multi-item arm in this file (list_pull_requests, list_issues, list_releases, list_gists, list_notifications). Making list_commits consistent with those eliminates the last remaining clone().into() in the file.


Improvement 2: Add Unit Tests for list_project_items / projects_list in response_paths.rs

Category: Test Coverage
File(s): guards/github-guard/rust-guard/src/labels/response_paths.rs
Effort: Medium (15–30 min)
Risk: Low

Problem

The list_project_items | projects_list arm of label_response_paths contains three distinct security-relevant code paths, none of which have any test coverage in the existing 8 tests for this file:

  1. ISSUE / PULL_REQUEST — extracts content sub-object, calls extract_repo_from_item, applies repo_visibility_secrecy_for_repo_id, then derives integrity from author_association_floor_from_str. Also has a fail-secure fallback when the repo cannot be determined.
  2. DRAFT_ISSUE / unknown type — skips repo context entirely; always returns writer_integrity(&arg_owner, ctx) with empty secrecy.
  3. items_path forwarding — the items_path returned by extract_items_array should propagate to PathLabelResult.items_path.

Suggested Change

Add at least three focused tests to the mod tests block:

#[test]
fn list_project_items_issue_type_gets_repo_scoped_secrecy_and_association_integrity() {
    let tool_args = json!({"owner": "octocat"});
    let response = json!({
        "items": [{
            "type": "ISSUE",
            "content": {
                "repository_url": "https://api.github.com/repos/octocat/hello-world",
                "author_association": "CONTRIBUTOR"
            }
        }]
    });
    let result = label_response_paths("list_project_items", &tool_args, &response, &ctx())
        .expect("should produce path labels");
    assert_eq!(result.labeled_paths.len(), 1);
    let entry = &result.labeled_paths[0];
    // CONTRIBUTOR association → at least reader-level integrity (non-empty)
    assert!(!entry.labels.integrity.is_empty(),
        "ISSUE item should have non-empty integrity; got {:?}", entry.labels.integrity);
    assert_eq!(entry.labels.description, "project-item:issue");
}

#[test]
fn list_project_items_draft_issue_gets_writer_integrity_and_empty_secrecy() {
    let tool_args = json!({"owner": "octocat"});
    let response = json!({
        "items": [{"type": "DRAFT_ISSUE", "title": "todo item"}]
    });
    let result = label_response_paths("list_project_items", &tool_args, &response, &ctx())
        .expect("should produce path labels");
    let entry = &result.labeled_paths[0];
    assert!(entry.labels.secrecy.is_empty(),
        "DRAFT_ISSUE should have empty secrecy; got {:?}", entry.labels.secrecy);
    // writer_integrity(owner) must be non-empty
    assert!(!entry.labels.integrity.is_empty(),
        "DRAFT_ISSUE should have non-empty integrity; got {:?}", entry.labels.integrity);
    assert_eq!(entry.labels.description, "project-item:draft_issue");
}

#[test]
fn projects_list_alias_behaves_identically_to_list_project_items() {
    let tool_args = json!({"owner": "octocat"});
    let response = json!({
        "items": [{"type": "PULL_REQUEST", "content": {
            "repository_url": "https://api.github.com/repos/octocat/hello-world",
            "author_association": "MEMBER"
        }}]
    });
    let r1 = label_response_paths("list_project_items", &tool_args, &response, &ctx());
    let r2 = label_response_paths("projects_list", &tool_args, &response, &ctx());
    // Both aliases must produce results with the same number of labeled paths
    assert_eq!(
        r1.as_ref().map(|r| r.labeled_paths.len()),
        r2.as_ref().map(|r| r.labeled_paths.len()),
        "projects_list alias must match list_project_items"
    );
}

Why This Matters

The list_project_items arm chooses between repo-scoped secrecy (for linked issues/PRs) and empty secrecy (for draft items) with no test safety net. A future refactor could accidentally swap the branches, flip the is_empty() fail-secure check, or break the projects_list alias — all silently. Tests also document the intended contract: that DRAFT items are always public-scoped, and that items with an unknown repo fail secure rather than defaulting to public.


Codebase Health Summary

  • Total Rust files: 10
  • Total lines: ~14,970
  • Areas analyzed: lib.rs, tools.rs, labels/mod.rs, labels/helpers.rs, labels/constants.rs, labels/tool_rules.rs, labels/response_paths.rs, labels/response_items.rs, labels/backend.rs
  • Areas with no further improvements: tools.rs (binary_search + sorted tests complete), lib.rs (parse_integrity + scope_string tests added)

Generated by Rust Guard Improver • Run: §26879421386

Generated by Rust Guard Improver · sonnet46 4.4M · ◷

  • expires on Jun 10, 2026, 10:46 AM UTC

Activity

  1. github-actions commented on Jun 3, 2026

    @github-actions
    ContributorAuthor

    🤖 This is an automated response from Repo Assist.

    Both improvements look solid. Copilot opened draft PR #6941 to address them. A few notes:

    Improvement 1 (list_commits Vec clone): The analysis is accurate — the three sister arms (list_pull_requests, list_issues, list_releases) already use the SharedLabels-first pattern, so list_commits is the outlier. Converting immediately to SharedLabels and cloning Arc (O(1)) rather than cloning the Vec (O(n) strings) is strictly better, and the PR applies this consistently.

    Improvement 2 (project-item tests): The three missing cases (ISSUE with repo context, DRAFT_ISSUE with owner-writer integrity + empty secrecy, and projects_list alias parity) are the right ones to pin down — the fail-secure branch in particular is easy to accidentally break in a refactor without a regression test guarding it.

    PR #6941 looks like it handles both. Worth a review pass to confirm the items_path contract test is also included.

    Generated by Repo Assist · sonnet46 1.7M · ◷

    Add this agentic workflows to your repo

    To install this agentic workflow, run

    gh aw add githubnext/agentics/workflows/repo-assist.md@851905c06e905bf362a9f6cc54f912e3df747d55
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions