Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds an IFC (Information Flow Control) label to the get_me tool’s call result metadata when InsidersMode is enabled, backed by a new pkg/ifc package implementing lattice structures and reader-based confidentiality labels.
Changes:
- Introduces a new
pkg/ifcpackage with core lattice types, inverse lattice support, and a reader-set powerset lattice used to construct IFC labels. - Adds a
LabelGetMe()helper that returns a “public + trusted” readers-based security label. - Updates
get_meto include the IFC label inCallToolResult.Metain insiders mode, and adds a focused test to validate meta behavior.
Show a summary per file
| File | Description |
|---|---|
| pkg/ifc/readers_lattice.go | Adds reader-set powerset lattice and ReadersSecurityLabel (incl. JSON serialization) for reader-based confidentiality. |
| pkg/ifc/lattice.go | Adds generic lattice interfaces and basic confidentiality/integrity lattice implementations plus product/inverse lattice helpers. |
| pkg/ifc/labelling_engine_readers.go | Adds LabelGetMe() helper for the get_me tool’s IFC label. |
| pkg/github/context_tools.go | Conditionally attaches the IFC label to get_me call result metadata when insiders mode is enabled. |
| pkg/github/context_tools_test.go | Adds tests asserting get_me includes/omits IFC meta depending on insiders mode. |
Copilot's findings
- Files reviewed: 5/5 changed files
- Comments generated: 7
| func (p *PowersetLattice[T]) Leq(other *PowersetLattice[T]) bool { | ||
| return p.subset.IsSubset(other.subset) | ||
| } | ||
|
|
||
| func (p *PowersetLattice[T]) Join(other *PowersetLattice[T]) *PowersetLattice[T] { | ||
| return &PowersetLattice[T]{ | ||
| subset: p.subset.Union(other.subset), | ||
| universe: p.universe, | ||
| } | ||
| } |
| finiteSet, ok := l.Confidentiality.Inner.subset.(*FiniteReaderSet[string]) | ||
| if !ok { | ||
| return nil | ||
| } | ||
|
|
||
| readers := make([]string, 0, len(finiteSet.members)) | ||
| for reader := range finiteSet.members { | ||
| readers = append(readers, reader) | ||
| } | ||
| return readers |
| result := MarshalledTextResult(minimalUser) | ||
| if deps.GetFlags(ctx).InsidersMode { | ||
| result.Meta = mcp.Meta{ | ||
| "ifc": ifc.LabelGetMe(), | ||
| } | ||
| } | ||
| return result, nil, nil |
| // PowersetLattice is a powerset lattice that can represent either a finite set or the universal set. | ||
| // subset and universe are represented using the ReaderSet interface. | ||
| // T must be comparable to be used as a map key. | ||
| type PowersetLattice[T comparable] struct { | ||
| subset ReaderSet[T] | ||
| universe ReaderSet[T] | ||
| } | ||
|
|
||
| // NewPowersetLattice constructs a PowersetLattice, checking that | ||
| // subset ⊆ universe. |
…tion, and tests - Fix grammar in ReadersSecurityLabelFromDict godoc - Sort GetReaders and FiniteReaderSet.String output for determinism - Fix godoc example to use UniversalReaders for public label - Panic on unsupported ReaderSet types in Union/Intersection/IsSubset - Add universe mismatch validation in PowersetLattice Join/Meet/Leq - Add comprehensive unit tests for pkg/ifc (lattice laws, serialization, panics)
| result := MarshalledTextResult(minimalUser) | ||
| if deps.GetFlags(ctx).InsidersMode { | ||
| result.Meta = mcp.Meta{ | ||
| "ifc": ifc.LabelGetMe(), |
There was a problem hiding this comment.
Heads-up: the wire format here is _meta.ifc with {integrity: "high"|"low", confidentiality: ["public"|...]}, but original spec _meta.ifc_label with {integrity: "trusted"|"untrusted", confidentiality: {readers: [...]}}. I'm fine matching your shape on the cli side), but should we update the issues to lock in ifc + high/low + flat list as the contract before we annotate more tools?
There was a problem hiding this comment.
Also this assigns result.Meta outright. If MarshalledTextResult ever starts populating Meta (or another decorator runs before this), we'd silently clobber it. cheaper to be defensive now and merge into an existing map than to debug later, something like if result.Meta == nil { result.Meta = mcp.Meta{} }; result.Meta["ifc"] = ifc.LabelGetMe(). wdyt?
| package ifc | ||
|
|
||
| // LabelGetMe returns a label for get_me: trusted, universal readers. | ||
| func LabelGetMe() ReadersSecurityLabel { |
There was a problem hiding this comment.
handler-level test in context_tools_test.go covers the integration nicely. Worth a one-liner unit test in pkg/ifc too. assert.True(t, LabelGetMe().IsHighIntegrity() && LabelGetMe().IsPublicConfidentiality())
I think it is very cheap to add now, and as labelling_engine_readers.go grows (LabelListIssues, LabelGetFileContents, …) we'll have a single place tracking per-tool label correctness without spinning up the full handler.
gokhanarkan
left a comment
There was a problem hiding this comment.
Some comments to make sure we align on the spec!
Summary
Adds Information Flow Control (IFC) labels to the
get_metool response, gated behind insiders mode. This is groundwork for FIDES integration — labelling tool outputs with integrity and confidentiality metadata so downstream consumers can enforce information flow policies.Why
FIDES requires each tool's output to carry a security label describing its integrity (trusted vs untrusted) and confidentiality (who can read it). The
get_metool is the first to get this treatment. Labels are returned inCallToolResult.Meta["ifc"]only when the server runs in insiders/experimental mode, keeping the stable API surface unchanged.What changed
pkg/ifc/package with lattice types for IFC labels:lattice.go— core lattice interface, confidentiality/integrity enums, product lattice, inverse latticereaders_lattice.go— powerset lattice over reader sets,ReadersSecurityLabelwith JSON marshalinglabelling_engine_readers.go—LabelGetMe()returning a public-trusted labelget_mehandler incontext_tools.gosetsresult.Meta["ifc"]whenInsidersModeis enabledTest_GetMe_IFC_InsidersModeverifying the label is present/absent based on insiders flagMCP impact
get_meresult now includes_meta.ifcwith{"integrity": "high", "confidentiality": ["public"]}in insiders mode only. No change to tool definition schema or stable behavior.Security / limits
Tool renaming
Note: if you are renaming tools, you must add the tool aliases. For more information on how to do so, please refer to the official docs.
Lint & tests
./script/lint./script/testDocs