Skip to content

Lpcox/print failed container logs#613

Merged
lpcox merged 36 commits intomainfrom
lpcox/print-failed-container-logs
Feb 3, 2026
Merged

Lpcox/print failed container logs#613
lpcox merged 36 commits intomainfrom
lpcox/print-failed-container-logs

Conversation

@lpcox
Copy link
Collaborator

@lpcox lpcox commented Feb 3, 2026

No description provided.

lpcox and others added 30 commits February 3, 2026 09:37
…e, and remote guard architecture

- Update Section 11.5 with complete GitHub MCP server tool classification
  - Add link to official github/github-mcp-server repository
  - Organize tools by toolset (context, repos, issues, PRs, actions, etc.)
  - Include get_me and all other context toolset operations

- Add Section 11.5.4: GitHub objects subject to DIFC labeling
  - Enumerate all object types (User, Repo, Commit, PR, Issue, etc.)
  - Categorize by domain (identity, repository, collaboration, CI/CD, security)

- Add Section 11.5.5: Label derivation rules per object type
  - Specify which MCP tools to call for each object
  - Define integrity and secrecy computation logic
  - Add summary table mapping objects to derivation tools

- Add Section 11.6: Guard interface implementation
  - Document Guard interface methods (Name, LabelResource, LabelResponse)

- Update Section 11.5 with complete GitHub MCP server tool classification
  - Add link to official github/github-mcp-server repository
  - Organize tools by toolset (context, repos, issuegua  - Add link to official github/github-mcp-server repository
  - Organiz,   - Organize tools by toolset (context, repos, issues, PRs,-   - Include get_me and all other context toolset operations

- Add Sectios
- Add Section 11.5.4: GitHub objects subject to DIFC labetru  - Enumerate all object types (User, Repo, Commit, PR, Issupr  - Categorize by domain (identity, repository, collaboration, CI/Cll
- Add Section 11.5.5: Label derivation rules per a calls (read-only, rate-limite  - Specify which MCP tools to call for each object
  - Def g  - D
- Test parseLabeledResource with simple, multiple, and empty labels
- Test parseCollectionLabeledData with labeled items
- Test RemoteGuard.Name() method
- Tests focus on data parsing logic (full integration tests would require mocking MCP protocol)

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
- Replace remote guard (MCP server) with WASM guard implementation
- Use wazero runtime for sandboxed WASM execution
- Guards run in isolated environment with no direct network access
- Guards call backend via host function for metadata
- Create sample Go guard that compiles to WASM
- Update configuration to support 'type = "wasm"' guards
- Add guard binding to servers via 'guard' field
- Guards cannot be invoked directly by agents (sandboxed)

Security improvements:
- WASM guards cannot make direct network calls
- Guards receive BackendCaller interface for controlled access
- Guards execute in sandboxed wazero runtime
- No credentials or direct backend access for guards

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
- Guards now run inside gateway process (not as CLI tool)
- Use wazero runtime for in-process sandboxed execution
- Guards export label_resource and label_response functions
- Host function call_backend allows guards to request backend metadata
- Sample guard demonstrates two-phase metadata protocol
- Sample guard calls backend to check repository visibility

TinyGo requirement:
- TinyGo required for proper WASM function exports (//export directive)
- Standard Go wasip1 target doesn't support function exports
- TinyGo 0.34 supports Go 1.19-1.23 (not yet Go 1.25)
- Framework is complete, waiting for TinyGo Go 1.25 support

Integration tests:
- Tests skip gracefully when TinyGo not available
- Test that standard Go WASM gives helpful error message
- Tests verify configuration parsing works
- Mock backend caller to test guard-backend interaction

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>

T_EDITOR=true git rebase --continue 2>&1
- Remove unused wasmFile variable declaration in test
- Remove unnecessary uint32 conversions in wasm.go
- All linting checks now pass

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
- Integration tests now check for Go 1.23 binaries (go1.23, go1.23.9, go1.23.10)
- Tests use GOROOT from Go 1.23 when compiling with TinyGo
- Makefile tries multiple Go 1.23 binary names
- Clear logging about which Go version is being used
- Updated README to document Go 1.23 + Go 1.25 setup

Key insight: WASM is version-independent. Guards compiled with Go 1.23
work perfectly with gateway compiled with Go 1.25. No version coupling.

Setup instructions:
- Gateway: Go 1.25 (current project requirement)
- Guards: Go 1.23 + TinyGo (for WASM compilation)
- Install: go install golang.org/dl/go1.23.9@latest && go1.23.9 download

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
- Remove unused isGo123Available() function
- Add comprehensive EXTERNAL_GUARD_QUICKSTART.md guide
- Document GitHub storage options (Releases, Packages, LFS)
- Provide step-by-step instructions for creating separate guard repo
- Include security best practices (checksums, signing, private repos)
- Document development workflow and troubleshooting
- Explain why GitHub Releases is recommended for production

Key points:
- GitHub Releases provides stable URLs for WASM files
- Private repositories supported with GITHUB_TOKEN
- SHA256 checksums recommended for integrity verification
- Current framework uses local 'path', 'url' support is future enhancement
- Guards can be developed independently from gateway

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Add ability to load WASM guards from remote URLs with:
- SHA256 checksum verification (required for security)
- Local caching by hash for efficiency
- GitHub token support (GITHUB_TOKEN env var) for private repos
- HTTP timeout configuration

Configuration:
- TOML: url, sha256, cache_dir fields in [guards.name]
- JSON: url, sha256, cacheDir fields in guards object
- Path and URL are mutually exclusive

New files:
- internal/guard/loader.go - WASM loading from path/URL with caching
- internal/guard/loader_test.go - comprehensive tests (22 tests)

Modified:
- internal/config/config.go - GuardConfig structs with new fields
- internal/guard/wasm.go - NewWasmGuardFromBytes constructor
- internal/server/unified.go - use loader for guard loading
- examples/guards/EXTERNAL_GUARD_QUICKSTART.md - updated docs
- examples/guards/sample-guard/README.md - fixed diagram alignment
New guardsdk package providing:
- LabelResourceRequest/Response types with helper methods
- GetString, GetInt, GetOwnerRepo helpers for tool arguments
- NewPublicResource, NewPrivateResource label constructors
- CallBackend, CallBackendTyped for backend MCP calls
- RegisterLabelResource, RegisterLabelResponse for handler setup
- Automatic WASM function exports

Also includes:
- examples/guards/guardsdk/example/ - SDK usage example
- examples/guards/guardsdk/README.md - SDK documentation
- Updated sample-guard with issue-specific labeling
- go.mod with lpcox/github-difc branch reference
Extend the upstream schema to support DIFC guard configuration:
- Add 'guard' property to stdioServerConfig, httpServerConfig, and customServerConfig
- Add 'guardConfig' definition for WASM guard structure (type, path, url)
- Add 'guards' property to root schema for defining guard configurations

This allows JSON configs like:
{
  "mcpServers": {
    "github": {
      "guard": "github-guard",
      ...
    }
  },
  "guards": {
    "github-guard": {
      "type": "wasm",
      "path": "/path/to/guard.wasm"
    }
  }
}
Sessions are now auto-created from the Authorization header regardless of
whether DIFC is enabled. This fixes the 'session not initialized' error
that occurred when using DIFC with guards.

Previously, DIFC mode required calling sys___init (deprecated) to create
a session. Now sessions are automatically created on first use, which is
consistent with the behavior when DIFC is disabled.

The session ID from the Authorization header is still used to track DIFC
labels per-agent - sessions are just created lazily instead of requiring
explicit initialization.
Path-based labeling solves the buffer size issue for large responses by
having guards return JSON Pointer paths + labels instead of copying data.

Changes:
- Add PathLabels types (PathLabels, PathLabel, PathLabelEntry, PathLabeledData)
- Implement RFC 6901 JSON Pointer parsing with proper escaping
- Add parsePathLabeledResponse() in WASM guard to handle new format
- Update guard SDK with PathLabel type and NewPathLabelResponseResponse()
- Update sample-guard to use path-based labeling for collections
- Add buffer retry logic with -2 error code for buffer too small
- Add comprehensive tests for path-based labeling

Benefits:
- Guards output ~100 bytes per item regardless of response size
- No data copying - gateway applies labels to original data
- Bounded output size eliminates buffer overflow issues
- Backward compatible with legacy Items format
Adds a new flag to control DIFC response filtering separately from DIFC
enforcement:

- Add --difc-filter CLI flag (default: false)
- Add MCP_GATEWAY_DIFC_FILTER environment variable
- Add DIFCFilter field to Config struct
- Add difcFilter field to UnifiedServer
- Update callBackendTool to conditionally filter based on difcFilter
- Add comprehensive tests for getDefaultEnableDIFC and getDefaultDIFCFilter
- Document new env var in AGENTS.md

Behavior:
- --enable-difc only: DIFC enforcement (access checks, label accumulation)
  but no response filtering
- --enable-difc --difc-filter: Full DIFC with fine-grained filtering
- --difc-filter without --enable-difc: Logs warning, no effect
Improve guard documentation with clear schema for label_response output:

- examples/guards/sample-guard/README.md:
  - Add path-based format (preferred) with full JSON example
  - Add schema table with field types and requirements
  - Mark legacy items format as deprecated

- examples/guards/guardsdk/README.md:
  - Add LabelResponseResponse and PathLabel struct definitions
  - Add complete JSON Schema (draft-07) for validation
  - Add Go code example for implementing path-based labeling

Path-based labeling uses JSON Pointer (RFC 6901) syntax and is more
efficient than the legacy format as it doesn't copy response data.
Add a logging callback that allows WASM guards to send log messages
back to the gateway host for debugging and monitoring.

Changes:
- Add host_log host function to wasm.go (levels: debug, info, warn, error)
- Add LogDebug/LogInfo/LogWarn/LogError/Logf to guardsdk
- Update all guard examples to demonstrate host logging usage
- Document host_log in EXTERNAL_GUARD_QUICKSTART.md

The host_log function signature:
  host_log(level uint32, msgPtr uint32, msgLen uint32)

Log messages appear in gateway debug output with DEBUG=guard:* and
are prefixed with the guard name for easy identification.
- Replace explicit 'public' with empty secrecy label per DIFC spec
- Replace explicit 'untrusted' with empty integrity label per DIFC spec
- Scope integrity tags to repositories (contributor:<repo>, maintainer:<repo>, project:<repo>)
- Scope secrecy tags to repositories (private:<repo>)
- Add guard responsibility for hierarchical tag expansion (section 3.1)
- Add ContributorIntegrity, MaintainerIntegrity, ProjectIntegrity helpers to SDK
- Update sample-guard, echo-guard, and guardsdk example to use new format
- Update integration tests to expect new DIFC-compliant labels
- Update documentation: github-difc.md, guardsdk README, EXTERNAL_GUARD_QUICKSTART
…coding issue

The 'invalid table access' error occurs during JSON marshaling in TinyGo 0.40.1
when compiled with Go 1.25. This is a known compatibility issue. Tests now
skip gracefully when this error is encountered rather than failing.
Add section 11.5 documenting how to configure initial secrecy and integrity
labels for agent sessions via:
- CLI flags (--session-secrecy, --session-integrity)
- Environment variables (MCP_GATEWAY_SESSION_SECRECY, MCP_GATEWAY_SESSION_INTEGRITY)
- Config file (gateway.session.secrecy, gateway.session.integrity)

This allows operators to assign appropriate clearances when agents connect,
enabling them to work with private repos at specified trust levels.

Also fixes section numbering (11.6 GitHub MCP Interface, 11.7 Guard Interface,
11.8 Remote Guard Architecture).
- Add Host Functions section to guardsdk/README.md documenting call_backend
  and host_log with SDK usage examples
- Expand Host Functions section in sample-guard/README.md with detailed
  documentation for both call_backend and host_log including low-level
  usage examples and log viewing instructions
WASM modules are single-threaded and cannot handle concurrent calls.
This adds a sync.Mutex to WasmGuard to serialize all calls to
LabelResource and LabelResponse, preventing race conditions when
multiple agents make concurrent requests through the same guard.

The mutex protects:
- The backend field which is mutated before each call
- The WASM module execution which is not thread-safe
The gateway was passing MCP-wrapped responses to guards for labeling:
  {"content":[{"type":"text","text":"{...actual JSON...}"}]}

But when the guard returned labeled items, the gateway tried to parse
the result as MCP format, causing:
  failed to convert result: json: cannot unmarshal array into Go value

Fix:
- Add unwrapMCPResponse() to extract actual JSON from MCP content wrapper
- Pass unwrapped data to guard's label_response function
- Store original MCP wrapper in CollectionLabeledData/FilteredCollectionLabeledData
- Rewrap results in MCP format via ToResult() when returning to client
- Propagate MCP wrapper through FilterCollection for filtered results

Files changed:
- internal/guard/wasm.go: Add unwrapMCPResponse(), modify LabelResponse
- internal/difc/resource.go: Add SetMCPWrapper(), modify ToResult() for rewrap
- internal/difc/evaluator.go: Propagate mcpWrapper in FilterCollection
…ateway

Add comprehensive documentation of the data format contract:

Section 11.7.5.1 - MCP Response Format Contract:
- Explains MCP content format
- Documents gateway unwrap/rewrap responsibilities
- Documents that guards work with clean JSON
- Includes contract summary table and rationale

Section 11.7.7 - DIFC Enforcement Flow:
- Updated from 6-phase to 7-phase flow
- Phase 4: Gateway unwraps MCP response
- Phase 5: Guard labels unwrapped data
- Phase 6: Filter and rewrap
- Added detailed phase 4-6 diagram

Section 11.7.8 - Guard Implementation Requirements:
- Added requirement 6: Work with unwrapped JSON data

Section 11.8.2 - MCP-Based Remote Guard Protocol:
- Clarified guard/label_response receives unwrapped JSON

This ensures the contract is completely specified and consistent
with the implementation fix in commit 26a738d.
lpcox added 6 commits February 3, 2026 09:40
Agent secrecy and integrity labels now remain fixed at their initial
session values. Automatic accumulation is disabled because:

1. Secrecy tainting caused uncontrolled label growth across operations
2. Integrity accumulation was semantically incorrect (integrity represents
   endorsement, not what data influenced the agent)

Changes:
- internal/difc/agent.go: AccumulateFromRead() is now a no-op with
  documentation explaining the rationale and future primitives
- internal/server/unified.go: Remove accumulation calls from Phase 6
- internal/difc/difc_test.go: Update test to verify labels are immutable
- docs/github-difc.md: Update Phase 7 to document immutable labels

Future versions will support explicit primitives for:
- Adding secrecy tags (when agent accepts sensitive data)
- Removing integrity tags (when agent performs untrusted operations)
When DIFC filtering is enabled (--difc-filter), read operations that fail
the coarse-grained check at Phase 2 now bypass the block and proceed to
the backend. Fine-grained per-item filtering at Phase 5 handles access
control instead of blocking the entire request.

Write operations always block on coarse-grained check failure since
write results cannot be filtered.

Adds comprehensive test coverage for the coarse-grained check bypass
behavior with 6 scenarios covering different combinations of:
- DIFC enabled/disabled
- Filtering enabled/disabled
- Read vs write operations
- Coarse check pass/fail
When DIFC filtering removes all items from a single-object response,
ToResult() now returns a proper empty MCP response instead of a bare
empty array. This fixes the JSON unmarshal error in convertToCallToolResult.

Also handles single MCP-formatted items (e.g., get_file_contents with
text+resource content) by returning them directly instead of wrapping
in an array.

Test cases:
- Empty filtered collection returns {"content":[{"type":"text","text":"[]"}]}
- Single MCP-formatted item returned directly
- Single non-MCP item still returns array for compatibility
- mcpWrapper path unchanged
When a container/process fails to launch, the stderr output is now captured
and logged to help diagnose issues. This is particularly useful for debugging
container startup failures where the error message is written to stderr.

The SDK's CommandTransport only uses stdin/stdout for the MCP protocol,
so we can safely capture stderr separately for debugging purposes.
Copilot AI review requested due to automatic review settings February 3, 2026 21:36
Copy link
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

This PR adds comprehensive DIFC (Decentralized Information Flow Control) functionality to the MCP Gateway, including WASM guard support, session label management, and container failure diagnostics. The changes enable policy-based access control through WebAssembly guards that can label resources and responses.

Changes:

  • Added WASM guard infrastructure with loader, registry, and execution runtime
  • Implemented DIFC session management with configurable initial labels
  • Added stderr capture for failed container diagnostics
  • Created extensive integration tests and demo scripts for guard development

Reviewed changes

Copilot reviewed 49 out of 53 changed files in this pull request and generated no comments.

Show a summary per file
File Description
internal/mcp/connection.go Added stderr capture for container failure diagnostics
internal/server/unified.go Major DIFC implementation with guard registration, filtering, and session auto-creation
internal/guard/loader.go WASM guard loader with URL/path support and checksum verification
internal/difc/*.go Path-based labeling, resource filtering, and agent registry enhancements
internal/config/*.go Config extensions for guards and session labels
internal/cmd/*.go CLI flags for DIFC features
test/integration/*_test.go Comprehensive integration tests for guards
examples/guards/* Sample guards, SDK, and documentation
scripts/*.sh Demo and automation scripts
Makefile Echo guard demo targets and lint exclusions

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@lpcox lpcox merged commit af1b842 into main Feb 3, 2026
10 checks passed
@lpcox lpcox deleted the lpcox/print-failed-container-logs branch February 3, 2026 21:41
lpcox added a commit that referenced this pull request Feb 3, 2026
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