Enforce readonly access to GitHub MCP server; remove dangerous-permissions-write feature flag#19092
Enforce readonly access to GitHub MCP server; remove dangerous-permissions-write feature flag#19092
Conversation
…flag - Remove 'dangerous-permissions-write: true' from test frontmatter - Remove empty 'features:' sections left after flag removal - Change write permissions to read in test workflow frontmatter - Remove 'read-only: false' from tools.github sections - Update compile_outputs_comment_test.go assertion to include discussions: write - Update permissions_validator_test.go for always-read-only behavior - Update github_remote_mode_test.go Codex URL expectations to mcp-readonly/ - Fix compiler_draft_test.go and github_remote_mode_test.go frontmatter Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e feature flag Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
@copilot run tests and fix issues from the last merge. Fix build-wasm |
There was a problem hiding this comment.
Pull request overview
Hardens GitHub MCP usage by enforcing read-only mode everywhere and removing the dangerous-permissions-write feature-flag bypass so workflow write permissions are always rejected.
Changes:
- Enforced GitHub MCP read-only behavior (config ignored at runtime; headers/env injected).
- Removed
dangerous-permissions-writefeature flag and updated validation/tests accordingly. - Updated numerous workflow fixtures/tests to use read permissions and to reflect the new enforcement.
Reviewed changes
Copilot reviewed 31 out of 31 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/workflow/xml_comments_test.go | Updates test frontmatter to remove write permissions / removed feature flag. |
| pkg/workflow/tools_validation.go | Adds validation rejecting tools.github.read-only: false. |
| pkg/workflow/step_summary_test.go | Updates test workflows to remove write permissions / removed feature flag. |
| pkg/workflow/permissions_validator_test.go | Updates test names to clarify read-only expectations. |
| pkg/workflow/permissions_validation.go | Forces GitHub tool to be treated as read-only (IsReadOnly() always true). |
| pkg/workflow/mcp_github_config.go | Makes getGitHubReadOnly() always return true and updates docs. |
| pkg/workflow/label_filter_test.go | Updates multiple test workflows to remove write permissions / removed feature flag. |
| pkg/workflow/github_remote_mode_test.go | Updates expected remote behavior (Codex uses /mcp-readonly/; removes read-only: false). |
| pkg/workflow/github_readonly_test.go | Updates expectation that read-only: false is ignored. |
| pkg/workflow/dangerous_permissions_validation_test.go | Removes bypass test cases; write is always an error now. |
| pkg/workflow/dangerous_permissions_validation.go | Removes feature-flag bypass logic for write permissions. |
| pkg/workflow/create_pull_request_ci_trigger_token_test.go | Updates test workflows to remove write permissions / removed feature flag. |
| pkg/workflow/compute_text_lazy_test.go | Updates multiple test workflows to remove write permissions / removed feature flag. |
| pkg/workflow/compiler_yaml_test.go | Updates invalid-YAML fixtures to remove write permissions / removed feature flag. |
| pkg/workflow/compiler_string_api.go | Adds validateGitHubReadOnly() to string-based compilation path. |
| pkg/workflow/compiler_poststeps_test.go | Updates test workflows to remove write permissions / removed feature flag. |
| pkg/workflow/compiler_orchestrator_workflow.go | Adds validateGitHubReadOnly() to file-based compilation path. |
| pkg/workflow/compiler_expression_size_test.go | Updates test workflows to remove write permissions / removed feature flag. |
| pkg/workflow/compiler_draft_test.go | Updates test workflows to remove write permissions / removed feature flag. |
| pkg/workflow/compile_outputs_pr_test.go | Updates test workflows to remove write permissions / removed feature flag. |
| pkg/workflow/compile_outputs_label_test.go | Updates test workflows to remove write permissions / removed feature flag. |
| pkg/workflow/compile_outputs_issue_test.go | Updates test workflows to remove write permissions / removed feature flag. |
| pkg/workflow/compile_outputs_comment_test.go | Updates test workflows and adjusts expected compiled permissions string. |
| pkg/workflow/compile_outputs_allowed_labels_test.go | Updates test workflows to remove write permissions / removed feature flag. |
| pkg/workflow/aw_info_tmp_test.go | Updates test workflow to remove write permissions / removed feature flag. |
| pkg/workflow/agentic_output_test.go | Updates test workflows to remove write permissions / removed feature flag. |
| pkg/workflow/action_sha_validation_test.go | Updates test workflow to remove write permissions / removed feature flag. |
| pkg/parser/mcp_test.go | Updates MCP extraction expectations to always include GITHUB_READ_ONLY=1. |
| pkg/parser/mcp.go | Always injects X-MCP-Readonly: true header and attempts to inject GITHUB_READ_ONLY=1 for Docker. |
| pkg/constants/constants_test.go | Removes DangerousPermissionsWriteFeatureFlag from feature flag constant tests. |
| pkg/constants/constants.go | Removes DangerousPermissionsWriteFeatureFlag constant. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
pkg/parser/mcp.go
Outdated
| // Check for custom GitHub configuration | ||
| if toolConfig, ok := toolValue.(map[string]any); ok { | ||
| // Check for read-only mode (only applicable in local/Docker mode) | ||
| if !useRemote && readOnly { | ||
| // When read-only is true, inline GITHUB_READ_ONLY=1 in docker args | ||
| // Always enforce read-only mode for GitHub MCP server (local/Docker mode) | ||
| if !useRemote { | ||
| // Inline GITHUB_READ_ONLY=1 in docker args to enforce read-only mode | ||
| config.Args = append(config.Args[:5], append([]string{"-e", "GITHUB_READ_ONLY=1"}, config.Args[5:]...)...) | ||
| } |
There was a problem hiding this comment.
Read-only enforcement for local/Docker mode is currently gated on toolValue being a map[string]any. If the workflow enables the GitHub tool using shorthand/null forms (e.g. tools: { github: null } / github:), this block won’t run and GITHUB_READ_ONLY=1 won’t be injected, undermining the “always read-only” guarantee. Enforce GITHUB_READ_ONLY=1 unconditionally whenever useRemote is false (independent of config shape), and keep the map-only block for parsing optional fields like allowed/version/args.
See below for a potential fix:
// Always enforce read-only mode for GitHub MCP server (local/Docker mode)
if !useRemote {
// Inline GITHUB_READ_ONLY=1 in docker args to enforce read-only mode
config.Args = append(config.Args[:5], append([]string{"-e", "GITHUB_READ_ONLY=1"}, config.Args[5:]...)...)
}
// Check for custom GitHub configuration
if toolConfig, ok := toolValue.(map[string]any); ok {
There was a problem hiding this comment.
Fixed in 85d388a. Moved the GITHUB_READ_ONLY=1 injection outside the map[string]any type guard — it now runs unconditionally whenever useRemote is false, covering all config shapes including shorthand github: true. Added a test case for the boolean shorthand form.
| func validateDangerousPermissions(workflowData *WorkflowData) error { | ||
| dangerousPermissionsLog.Print("Starting dangerous permissions validation") | ||
|
|
||
| // Check if the feature flag is enabled | ||
| featureEnabled := isFeatureEnabled(constants.DangerousPermissionsWriteFeatureFlag, workflowData) | ||
| if featureEnabled { | ||
| dangerousPermissionsLog.Print("dangerous-permissions-write feature flag is enabled, allowing write permissions") | ||
| return nil | ||
| } | ||
|
|
||
| // Parse the top-level workflow permissions | ||
| if workflowData.Permissions == "" { | ||
| dangerousPermissionsLog.Print("No permissions defined, validation passed") |
There was a problem hiding this comment.
Even though the feature-flag bypass was removed, this function still logs "Found %d write permissions without feature flag" later on. That message is now misleading for debugging; update it to remove the feature-flag wording (or delete the log line if it no longer adds value).
There was a problem hiding this comment.
Fixed in 85d388a. Updated the log message from "Found %d write permissions without feature flag" to "Found %d write permissions".
…nly: false from workflow files Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Fixed in db1a7f4. The |
…ean up stale log message Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
pkg/parser/mcp.go
Outdated
|
|
||
| // Always enforce read-only mode for GitHub MCP server (local/Docker mode) | ||
| // This must be unconditional to cover shorthand/null tool config forms. | ||
| if !useRemote { |
There was a problem hiding this comment.
@copilot move code into the branch that configures the local MCP
There was a problem hiding this comment.
Fixed in dd2fcfb. Moved -e GITHUB_READ_ONLY=1 directly into the Args slice in the else branch that configures the local Docker MCP, eliminating the separate post-block injection. It now mirrors how X-MCP-Readonly: true is set directly in the remote if useRemote branch.
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Tests pass (dd2fcfb). All 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:
|
…ns-write from test fixtures Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Fixed in fbab3ca. The integration tests in |
…ons from test fixtures Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Fixed in c01d42b. Two more integration test files had |
|
@copilot fix tests CI / Integration: CLI Completion & Other (pull_request) |
- compiler_cache_test: change expected custom permissions from write to read - permissions_import_test: update ValidateIncludedPermissions test cases to use read permissions; rename Test3 to 'Missing permission from imported workflow fails validation' using metadata:read to test missing case; fix ExtractPermissionsFromContent expected value - strict_mode_test: restore write permissions in write-refused tests, update errorMsg to 'strict mode: write permission'; use network wildcard for no-strict-field and CLI-precedence tests since write is now globally forbidden - Remove features: dangerous-permissions-write: true from all test fixtures - Update all other test files to use read permissions throughout Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixed in 58d83a1. The 5 failing CI jobs all had integration tests in
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:
|
…de test generation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Fixed in 67d3e21. 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:
|
…ngs for write→read codemod tests Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Fixed in 668953c. The batch 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:
|
DangerousPermissionsWriteFeatureFlagconstant frompkg/constants/constants.godangerous_permissions_validation.go(always error on write permissions)mcp_github_config.go(getGitHubReadOnlyalways returnstrue)permissions_validation.goIsReadOnly()to always returntruevalidateGitHubReadOnlyvalidation intools_validation.goto error onread-only: falsecompiler_orchestrator_workflow.goandcompiler_string_api.gopkg/parser/mcp.goto always use read-only for GitHub MCP (remote and local modes)GITHUB_READ_ONLY=1directly into theelsebranch (local Docker config) inpkg/parser/mcp.gopkg/parser/mcp_test.gotest case for booleantrueshorthand to confirm read-only is enforceddangerous_permissions_validation.go: "without feature flag" removed.github/workflows/example-permissions-warning.md- removeread-only: falseanddangerous-permissions-write: true, update body text.github/workflows/daily-issues-report.md- removedangerous-permissions-write: true.github/workflows/daily-observability-report.md- removedangerous-permissions-write: true.github/workflows/daily-performance-summary.md- removedangerous-permissions-write: true.github/workflows/org-health-report.md- removedangerous-permissions-write: truepkg/workflow/andpkg/cli/: changeissues/contents/pull-requests: write→read, removedangerous-permissions-write: true, remove orphanedfeatures:keyscompiler_cache_test.goTestCustomPermissionsOverrideDefaults: update assertions fromwrite→readpermissions_import_test.go: updateAll_required_permissions_present_passes_validationto useread, fixInsufficient_permission_level_fails_validationto test missing permission, fixSimple_permissionsexpected valuestrict_mode_test.go: restorewriteperms in strict mode write-rejection tests + update error messages; change "no strict field defaults to strict mode" andTestCLIStrictFlagTakesPrecedenceto use network wildcard"*"to test strict mode (since write is now globally forbidden)compiler_orchestrator_test.goTestParseWorkflowFile_StrictMode: remove orphaned\nfeatures:from dynamically-generated test contentcodemod_permissions_test.go: restorewritevalues incontentstrings forTestWritePermissionsCodemod_MapFormat,_MultipleWritePermissions,_PreservesIndentation,_PreservesComments(batch fix incorrectly changed them fromwritetoread, but these tests specifically test the write→read codemod transformation)pkg/parser,pkg/workflow,pkg/cli,pkg/constants)Original prompt
💡 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.
✨ PR Review Safe Output Test - Run 22552233163