feat: Add GitHub DIFC enforcement with WASM guards, guard policies, and LabelAgent integration#1674
feat: Add GitHub DIFC enforcement with WASM guards, guard policies, and LabelAgent integration#1674
Conversation
Restore config extension features for DIFC session label configuration: New CLI flags: - --enable-config-extensions: Gate for enabling DIFC-related config features - --session-secrecy: Comma-separated initial secrecy labels for agent sessions - --session-integrity: Comma-separated initial integrity labels for agent sessions New environment variables: - MCP_GATEWAY_CONFIG_EXTENSIONS: Enable config extensions - MCP_GATEWAY_SESSION_SECRECY: Initial secrecy labels - MCP_GATEWAY_SESSION_INTEGRITY: Initial integrity labels Features: - SessionConfig struct added to GatewayConfig for TOML/JSON config support - Validation that session label flags require --enable-config-extensions - NewAgentRegistryWithDefaults() called with configured labels - Tests for all new helper functions
T_EDITOR=true git rebase --continue && git status --short --branch
Restores WASM guard implementation and path labeling from commit 0f1873a that was inadvertently reverted in commit 04f678e. Restored files: - internal/guard/wasm.go: WASM guard with mutex for thread safety - internal/difc/path_labels.go: Path-based labeling (JSON Pointer RFC 6901) - internal/difc/path_labels_test.go: Comprehensive tests for path labeling This enables loading WASM guards from config: { "guards": { "github-guard": { "type": "wasm", "path": "/path/to/guard.wasm" } } }
Tests the GitHub guard WASM file at /Users/lpcox/Desktop/ai/github-guard/github-guard-rust.wasm Verifies: - Read operations: search_repositories, get_issue, list_commits, get_file_contents, list_branches - Write operations: create_issue, push_files, create_or_update_file, create_pull_request - LabelResponse for search results with path-based labeling - Concurrent access (WASM module serialization) Tests are skipped if the WASM file is not present.
The createGuardFromConfig function was calling guard.CreateGuard('wasm')
which looks for a registered factory, but the path to the WASM file was
never passed. Now directly calls guard.NewWasmGuard() with the config path.
This enables guards configured in JSON like:
"guards": {
"github-guard": {
"type": "wasm",
"path": "/guard/github-guard-rust.wasm"
}
}
In filter/propagate mode, read operations should proceed to the backend even if coarse-grained checks fail, because LabelResponse() provides per-item labels and Phase 5 filtering can then filter/propagate those specific items based on their actual data labels. This restores the behavior from commit 884c490 which was inadvertently reverted in commit 04f678e.
Propagate mode now correctly handles labels: - Secrecy: UNION - agent becomes tainted with all secret classifications from data it reads (agent_secrecy ∪ resource_secrecy) - Integrity: INTERSECTION - agent's trustworthiness is reduced to minimum (agent_integrity ∩ resource_integrity) Also fixed: - Label accumulation only happens in propagate mode (not filter/strict) - convertToCallToolResult now handles array responses and empty content - Added Label.Intersect() method for integrity intersection
- Add DIFC Label Rules section explaining secrecy and integrity flow rules - Add DIFC Modes section describing strict, filter, and propagate modes - Clarify format detection behavior for WASM guards - Update filtering behavior documentation to match code - Fix NoopGuard to return OperationReadWrite instead of OperationWrite
- unified.go: Fix LabelResponse() calling logic per spec: - Skip LabelResponse for write operations (all modes) - Skip LabelResponse for read-write in strict mode - Block entire response in strict mode if any item filtered - Apply De Morgan's law per staticcheck QF1001 - guard_test.go: Update NoopGuard tests to expect OperationReadWrite - config_difc_test.go: Use assert.Empty() instead of nil/len check (S1009) - agent.go: Fix godoc comment formatting - Remove wasm_github_test.go (pre-existing test data format issue)
Guards label the inner JSON structure of MCP responses (e.g., /items/0),
but the gateway was trying to resolve these paths against the MCP wrapper
({content:[{text:...}]}), causing 'path not found' errors.
Changes:
- Add unwrapMCPResponse() to detect and extract inner JSON from MCP format
- PathLabeledData now stores both OriginalData and UnwrappedData
- getItems() navigates paths using UnwrappedData
- Add comprehensive tests for MCP unwrapping
Added debug logging to track tool arguments being passed to guards: - wasm.go: Log args value and full input JSON with byte count - unified.go: Log args in callBackendTool This helps diagnose issues where guards may not be receiving tool arguments correctly.
…n requireGuardPolicyIfGuardEnabled - test/integration/difc_config_test.go: replace 13200+len(name)%100 with getFreePort(t) helper to eliminate port collisions between subtests of equal name length and with other processes - internal/server/unified.go: requireGuardPolicyIfGuardEnabled now uses resolveGuardPolicy(serverID) so that policy provided via global override (cfg.GuardPolicy from CLI/env) or via GuardConfig.Policy is accepted, not just ServerConfig.GuardPolicies Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot is the flag "--enable-difc" off by default, in other words is difc enforcement and loading mcp guards off by default? |
Yes,
So out of the box, with no configuration, DIFC enforcement and meaningful guard evaluation are both inactive. They only activate when |
|
@copilot what happens to sys tools if difc is enabled? they should remain off and unexposed at all times if they are not. |
When When DIFC is disabled (the default), neither tool is registered or visible — the If the intent is that these tools should never appear in |
|
@copilot the sys tools should be considered deprecated since the agent labels are set when a guard is initialized via the label_agent call. keep the implementation but otherwise they should not be exposed to the agent. also please make sure that when validating an allow-only config the string "allow-only" (with a dash) is used and not "allowonly" (no dash) for example the following should pass validation |
…anonical guard policy key Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Done in commit Sys tools hidden from agents:
"allow-only": {
"repos": repos,
"min-integrity": integrity
}Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
The "allow-only" object in the comment below is not actually valid since values for "repos" and "min-integrity" are non-conformant with the schema and spec. Can you confirm that aside from changing "allowonly" to "allow-only" validation did not change? |
Confirmed — the validation logic is identical to before. The only changes in
All of the following rules are completely unchanged:
The example in my previous reply used placeholder variable names ( |
AddSecrecyTags/DropIntegrityTag/DropIntegrityTagsbypassLabel.mu— addLabel.Remove/RemoveAll, use thread-safe methods throughoutLabel.RemoveandLabel.RemoveAllTestAgentLabels_ConcurrentBulkMutationsTestDIFCEnvironmentVariables— use ephemeral ports viagetFreePort(t)helperrequireGuardPolicyIfGuardEnabledto useresolveGuardPolicycovering all policy sources (global override, server-specific, guard config)sys___init/sys___list_serversnever appear intools/list; remove/mcp/sysroute from routed mode regardless of DIFC state"allow-only"(with dash) as the canonical key; legacy"allowonly"(no dash) still accepted for backward compatibility;MarshalJSONoutputs"allow-only"; all error messages updated💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.