Skip to content

Add ifc label for search_issues tool#2456

Open
gokhanarkan wants to merge 2 commits into
mainfrom
gokhanarkan/fides-search-issues
Open

Add ifc label for search_issues tool#2456
gokhanarkan wants to merge 2 commits into
mainfrom
gokhanarkan/fides-search-issues

Conversation

@gokhanarkan
Copy link
Copy Markdown
Member

Emits an IFC SecurityLabel on the search_issues tool result when the InsidersMode flag is enabled, mirroring the pattern landed for get_me in #2432, list_issues in #2453, and get_file_contents in #2454.

Refs github/copilot-mcp-core#1623, github/copilot-mcp-core#1389. One of the ingress tools listed in #1623's tool table.

Chained on #2454. Base is currently gokhanarkan/fides-get-file-contents because this PR reuses the FetchRepoIsPrivate and FetchRepoCollaborators helpers added there. GitHub will auto-retarget the base to main once #2454 merges.

What this PR does

Search results may span multiple repositories, so _meta.ifc for search_issues is the IFC join of the per-repository labels:

  • Integrity is always untrusted (issues are user-authored).
  • Confidentiality follows the lattice join (least upper bound):
    • If any matched repository is public → ["public"] (the public side dominates).
    • Otherwise → intersection of the collaborator sets across all matched private repositories (a reader must have access to every matched private repo).
    • Empty result sets → ["public"] (no data leaked).

If any per-repo visibility or collaborators lookup fails, the label is omitted entirely (consistent with get_file_contents) to avoid misclassifying the result.

New shared helpers

  • ifc.LabelSearchIssues(repoVisibilities []bool, readerSets [][]string) in pkg/ifc/ifc.go — pure join function, separately unit-tested.
  • searchHandler in pkg/github/search_utils.go gains an additive variadic searchOption hook so SearchIssues can attach _meta.ifc without duplicating the search call. search_pull_requests is unaffected — it passes no options and continues to behave exactly as before.

Empty-intersection semantics (called out for reviewers)

If two private repos have zero overlapping collaborators, the joined reader set is []. We emit confidentiality: [] rather than skipping the label — this matches the IFC math (no one can read) and lets the client engine decide what to do. Worth a sanity-check from @JoannaaKL.

Cost note

A search returning 30 results across 30 different private repos = 60 API calls (visibility + collaborators each). Bounded but not free; cache lands in a follow-up per the standing agreement.

Tests

  • Test_LabelSearchIssues in new pkg/ifc/ifc_test.go — table-driven coverage of the join math (empty, single public, mixed, intersecting private, no overlap, dedupe).
  • Test_SearchIssues_IFC_InsidersMode in pkg/github/issues_test.go with 6 subtests:
    1. Insiders off → result.Meta == nil.
    2. Insiders on, single public repo → integrity=untrusted, confidentiality=["public"].
    3. Insiders on, mixed public + private → ["public"] (public wins).
    4. Insiders on, two private repos with intersecting collaborators → asserts the intersection.
    5. Insiders on, visibility lookup fails (500) → no ifc meta.
    6. Insiders on, empty results → ["public"].

Validation

  • go test -race ./... — green.
  • gofmt -s clean; go vet ./... clean.
  • (./script/lint itself fails locally with a pre-existing golangci-lint Go-version mismatch unrelated to this change.)
  • No tool schema/annotation changes → no toolsnap or README regeneration needed.

Copilot AI review requested due to automatic review settings May 12, 2026 11:03
@gokhanarkan gokhanarkan requested a review from a team as a code owner May 12, 2026 11:03
Copy link
Copy Markdown
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

Adds IFC _meta.ifc labeling to the search_issues tool when InsidersMode is enabled, following the established insiders-only metadata pattern for other ingress tools.

Changes:

  • Added ifc.LabelSearchIssues(...) (plus intersectReaders) to join per-repo labels for search_issues results.
  • Extended the shared searchHandler with an additive post-processing hook so callers can attach metadata without duplicating the search logic.
  • Updated search_issues to compute/join per-repo visibility + collaborators and attach the resulting IFC label; added unit and integration-style tests.
Show a summary per file
File Description
pkg/ifc/ifc.go Adds label-join helper for search_issues and reader-set intersection logic.
pkg/ifc/ifc_test.go Adds table-driven tests for LabelSearchIssues join semantics.
pkg/github/search_utils.go Introduces optional post-processing hook for searchHandler results.
pkg/github/issues.go Wires insiders-only IFC labeling into search_issues via the new post-process hook.
pkg/github/issues_test.go Adds insiders-mode test coverage for search_issues IFC behavior.

Copilot's findings

  • Files reviewed: 5/5 changed files
  • Comments generated: 3

Comment thread pkg/ifc/ifc.go
Comment thread pkg/github/issues.go Outdated
Comment thread pkg/github/issues_test.go
Base automatically changed from gokhanarkan/fides-get-file-contents to main May 12, 2026 14:42
gokhanarkan added a commit that referenced this pull request May 12, 2026
- LabelSearchIssues now returns (SecurityLabel, bool); the bool is
  false when len(repoVisibilities) != len(readerSets), so callers can
  omit the label rather than emit one computed from inconsistent
  inputs.
- searchIssuesIFCPostProcess no longer substitutes [owner] when the
  collaborators API returns an empty list. The substitution was
  inconsistent with the cross-repo intersection semantics: the owner
  could appear in another matched private repo's collaborator list and
  thereby widen the joined reader set incorrectly. Empty collaborator
  sets are now passed through unchanged.
- Add a subtest exercising the collaborators-failure branch (500 on
  /repos/{owner}/{repo}/collaborators), asserting the tool still
  succeeds and result.Meta["ifc"] is absent.
- Extend the LabelSearchIssues table tests with the slice-length
  mismatch case.

Addresses the three Copilot findings on #2456.
gokhanarkan added a commit that referenced this pull request May 12, 2026
Emits an IFC SecurityLabel on the issue_read tool result when the
InsidersMode flag is enabled, mirroring the pattern landed for get_me
in #2432, list_issues in #2453, get_file_contents in #2454, and
search_issues in #2456.

issue_read operates on a single issue in a single repository so the
label has the same per-repo semantics as list_issues; the helper
ifc.LabelListIssues is reused directly. Integrity is always untrusted
(issue contents, comments, and label descriptions are user-authored).
Public repos are labelled PublicUntrusted; private repos are labelled
PrivateUntrusted with the repository's collaborator logins, falling
back to [owner] when the collaborators lookup fails.

The IssueRead handler dispatches to four sub-functions (GetIssue,
GetIssueComments, GetSubIssues, GetIssueLabels). The IFC label is
attached at the dispatch site via a single attachIFC closure, so all
four method branches emit the label without changes to the underlying
helpers. Visibility-lookup failures cause the label to be omitted
entirely (consistent with get_file_contents and search_issues).

A future cleanup PR can extract attachIFC into a shared helper now that
get_file_contents, search_issues, and issue_read use near-identical
closures; intentionally not bundled here to keep the diff minimal.

Refs github/copilot-mcp-core#1623, github/copilot-mcp-core#1389.

Note: chained on #2456 (gokhanarkan/fides-search-issues), which is in
turn chained on #2454. GitHub will retarget the base to main once those
merge.
Emits an IFC SecurityLabel on the search_issues tool result when the
InsidersMode flag is enabled, mirroring the pattern landed for get_me
in #2432, list_issues in #2453, and get_file_contents in #2454.

Search results may span multiple repositories, so the label is the IFC
join of the per-repository labels:

  - Integrity is always untrusted (issues are user-authored).
  - If any matched repository is public, the joined readers are
    ["public"] (the public side dominates the lub).
  - Otherwise the joined readers are the intersection of the
    collaborator sets across all matched private repositories.
  - Empty result sets are labelled public-untrusted (no data leaked).

The shared searchHandler in search_utils.go gains an additive variadic
'searchOption' hook so SearchIssues can attach _meta.ifc without
duplicating the search call. SearchPullRequests is unaffected; it does
not pass any options.

If any per-repository visibility or collaborators lookup fails the label
is omitted entirely, consistent with get_file_contents, to avoid
misclassifying the result.

Refs github/copilot-mcp-core#1623, github/copilot-mcp-core#1389.

Note: this PR is chained on #2454 (gokhanarkan/fides-get-file-contents)
because it depends on the FetchRepoIsPrivate and FetchRepoCollaborators
helpers introduced there. GitHub will retarget the base to main once
#2454 merges.
- LabelSearchIssues now returns (SecurityLabel, bool); the bool is
  false when len(repoVisibilities) != len(readerSets), so callers can
  omit the label rather than emit one computed from inconsistent
  inputs.
- searchIssuesIFCPostProcess no longer substitutes [owner] when the
  collaborators API returns an empty list. The substitution was
  inconsistent with the cross-repo intersection semantics: the owner
  could appear in another matched private repo's collaborator list and
  thereby widen the joined reader set incorrectly. Empty collaborator
  sets are now passed through unchanged.
- Add a subtest exercising the collaborators-failure branch (500 on
  /repos/{owner}/{repo}/collaborators), asserting the tool still
  succeeds and result.Meta["ifc"] is absent.
- Extend the LabelSearchIssues table tests with the slice-length
  mismatch case.

Addresses the three Copilot findings on #2456.
@gokhanarkan gokhanarkan force-pushed the gokhanarkan/fides-search-issues branch from 279a59b to 1df735c Compare May 12, 2026 15:04
gokhanarkan added a commit that referenced this pull request May 12, 2026
Emits an IFC SecurityLabel on the issue_read tool result when the
InsidersMode flag is enabled, mirroring the pattern landed for get_me
in #2432, list_issues in #2453, get_file_contents in #2454, and
search_issues in #2456.

issue_read operates on a single issue in a single repository so the
label has the same per-repo semantics as list_issues; the helper
ifc.LabelListIssues is reused directly. Integrity is always untrusted
(issue contents, comments, and label descriptions are user-authored).
Public repos are labelled PublicUntrusted; private repos are labelled
PrivateUntrusted with the repository's collaborator logins, falling
back to [owner] when the collaborators lookup fails.

The IssueRead handler dispatches to four sub-functions (GetIssue,
GetIssueComments, GetSubIssues, GetIssueLabels). The IFC label is
attached at the dispatch site via a single attachIFC closure, so all
four method branches emit the label without changes to the underlying
helpers. Visibility-lookup failures cause the label to be omitted
entirely (consistent with get_file_contents and search_issues).

A future cleanup PR can extract attachIFC into a shared helper now that
get_file_contents, search_issues, and issue_read use near-identical
closures; intentionally not bundled here to keep the diff minimal.

Refs github/copilot-mcp-core#1623, github/copilot-mcp-core#1389.

Note: chained on #2456 (gokhanarkan/fides-search-issues), which is in
turn chained on #2454. GitHub will retarget the base to main once those
merge.
gokhanarkan added a commit that referenced this pull request May 12, 2026
Emits an IFC SecurityLabel on the search_repositories tool result when
the InsidersMode flag is enabled, mirroring the pattern landed for
get_me, list_issues, get_file_contents, search_issues, and issue_read.

Per the spec in github/copilot-mcp-core#1623, the label is
PublicUntrusted() regardless of whether matched repositories are
private. Repository search is treated as a discovery surface: matched
repositories are by definition already accessible to the caller, so
the joined readers are universal. Integrity is untrusted because
repository names, descriptions, and topics are user-authored.

Implementation note: SearchRepositories has its own handler distinct
from the shared searchHandler used by SearchIssues, so the IFC attach
is wired inline at the success return rather than via the postProcess
hook added in #2456.

Refs github/copilot-mcp-core#1623, github/copilot-mcp-core#1389.

Note: chained on #2457 (gokhanarkan/fides-issue-read), which is in
turn chained on #2456. GitHub will retarget the base to main once
those merge.
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