Skip to content

feat(guard): add DIFC labeling for GitHub Projects tools #2094

@lpcox

Description

@lpcox

Problem

Guard policies block all org-level GitHub Projects access. All 4 project read tools (list_projects, get_project, list_project_fields, list_project_items) return empty results when guard policies are active.

Upstream report: github/agentic-workflows#90

Root Cause: Two Independent Bugs

Bug 1: Scope mismatch — Project tools are unrecognized by the guard (fall through to default case in tool_rules.rs). The default case assigns unscoped baseline integrity ["none"], but the agent's tags are scoped (e.g., ["none:github"] for repos: ["github/*"]). Since tag comparison is exact string matching, "none" ≠ "none:github" → blocked.

This breaks even with min-integrity: none.

Bug 2: Integrity level — Even when scope alignment is fixed, project resources only get baseline none integrity (no author_association field). Any min-integrity above none blocks all project access.

Reproduction Matrix (from upstream issue)

repos min-integrity Projects work? Failure reason
"all" none ✅ Yes Both tags are unscoped "none" — exact match
["github/*"] none ❌ No Agent: "none:github" vs Resource: "none" — scope mismatch
"all" approved ❌ No Agent needs "approved" but resource only has "none"

Proposed Solution

1. Recognize Project Tools in tool_rules.rs

Add explicit match arms for:

  • list_projects (read)
  • get_project (read)
  • list_project_fields (read)
  • list_project_items (read)

Already recognized (write operations):

  • add_project_item, delete_project_item (write)
  • update_project_item (read-write)

2. Secrecy Labels

Use the project's public boolean (available in GitHub API ProjectV2 object):

  • Private project → private:<owner> (e.g., private:github)
  • Public project → [] (empty, unrestricted)

For list_project_items, items inherit secrecy from their underlying repo (issues/PRs have repository_url). Draft issues inherit from the project's visibility.

3. Integrity Labels

GitHub Projects have creator fields at multiple levels (ProjectV2 and ProjectV2Item):

Tool Integrity Source Level Rationale
list_projects Project creator approved:<scope> Creating projects requires org membership
get_project Project creator approved:<scope> Same
list_project_fields Project creator (inherited) approved:<scope> Field definitions are structural metadata
list_project_items (issues/PRs) Issue/PR author_association Varies per item Reuses existing labeling logic
list_project_items (draft issues) Item creator approved:<scope> Adding items requires project access (org member)

Creator integrity mapping: Since creating/managing projects requires org membership, creators map to approved (equivalent to MEMBER author_association).

4. Scope Alignment (Critical)

Resource integrity tags must use the same scope token as the agent. When the guard handles project tools:

  • Extract owner from tool args (projects are org-scoped, not repo-scoped)
  • Pass through normalize_scope(owner, ctx) to align with agent's scope token
  • Example: policy repos: ["github/*"] → agent has "none:github" → resource gets "approved:github" (not bare "approved")

For list_project_items, each item's scope comes from its underlying repository.

5. Response Labeling in response_paths.rs

Add per-item labeling for list_project_items since it returns a heterogeneous collection:

  • Issues/PRs: Label using content.author_association and content.repository_url (extract owner/repo)
  • Draft issues: Label using item creator and project owner

Implementation Scope

Guard (Rust WASM)

  • tool_rules.rs: Add match arms for 4 project read tools with secrecy/integrity
  • response_paths.rs or response_items.rs: Add per-item labeling for list_project_items
  • helpers.rs: Potentially add project_creator_integrity() helper

Testing

  • Unit tests for each project tool's labeling
  • Integration test with repos: ["org/*"] + min-integrity: approved policy
  • Verify items with different content types (issue, PR, draft) get correct labels

Notes

  • Project item types: issues, pull requests, and draft issues
  • Only list_project_items returns per-item repo context; the other 3 are purely org-level
  • The existing write tool recognition (add_project_item, delete_project_item, update_project_item) does not need changes

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions