Skip to content

Reject invalid boolean values for GITHUB_READ_ONLY and other bool env vars - #3750

Open
orshih6 wants to merge 4 commits into
github:mainfrom
orshih6:contribot/issue-3747
Open

orshih6 wants to merge 4 commits into
github:mainfrom
orshih6:contribot/issue-3747

Conversation

@orshih6

@orshih6 orshih6 commented Nov 9, 2026 •

Copy link
Copy Markdown

Boolean settings such as GITHUB_READ_ONLY and GITHUB_LOCKDOWN_MODE were read with viper.GetBool. It runs the value through strconv.ParseBool and returns false if parsing fails. So GITHUB_READ_ONLY=yes, on, enabled or a typo like tru quietly left read-only mode off and exposed every write tool. viper also treats an empty variable (GITHUB_READ_ONLY=) as unset, which has the same effect. The --read-only=yes flag form already fails, because pflag parses it strictly.

This change adds validateBoolSettings, which takes the raw viper value for each bool key. When that value is a string (which in practice means it came from the environment), it checks it with strconv.ParseBool. A variable that is set but empty is rejected too. Both checks are skipped when the matching flag was passed explicitly, because the flag overrides the env var. On failure it returns an error naming the variable, e.g. invalid value "yes" for GITHUB_READ_ONLY: must be a boolean (1, t, T, true, TRUE, True, 0, f, F, false, FALSE, False). The stdio and http commands call it at the start of RunE, so startup exits non-zero just as it does for a bad flag. It covers read-only, lockdown-mode, insiders, export-translations and enable-command-logging, plus scope-challenge and trust-proxy-headers for http. list-scopes checks read-only as well.

Valid values behave as before, since the check uses the same parser as GetBool. An unset env var is still false, and an explicit flag still overrides the env var. A note on the accepted values was added to docs/server-configuration.md.

Behaviour change (worth a release-note line): an invalid or empty value in any of these bool env vars, not only read-only and lockdown, now stops startup instead of being treated as false. That includes values that used to be accepted silently, such as GITHUB_INSIDERS=yes, and a variable that is set but empty, such as GITHUB_READ_ONLY= or docker run -e GITHUB_READ_ONLY=. The docs note says so explicitly.

Testing:

  • A new table-driven test, TestValidateBoolSettingsFromEnv, covers GITHUB_READ_ONLY and GITHUB_LOCKDOWN_MODE. It checks that 1/true/TRUE/True/t/T/0/false/FALSE/False/f/F parse correctly, that an empty value and yes/on/enabled/tru return an error listing every accepted value, that an explicit flag overrides an empty env var, and that an unset variable gives false. The test clears every checked variable first, so the environment it runs in doesn't affect the result.
  • go test ./cmd/github-mcp-server/ (also run with GITHUB_READ_ONLY=1 GITHUB_INSIDERS=yes set in the outer environment) and script/lint pass.
  • Manual check with the built binary: GITHUB_READ_ONLY=yes ... stdio, GITHUB_READ_ONLY=yes ... list-scopes and GITHUB_READ_ONLY= ... list-scopes exit 1 with the error. GITHUB_READ_ONLY=1 works, and GITHUB_READ_ONLY= ... list-scopes --read-only=false still runs because the flag wins.

Fixes #3747


This change was prepared with an AI coding agent (Claude) and reviewed by me before submitting. I'm happy to make any changes you'd like.

… vars

Signed-off-by: Бат-Орших <34618353+orshih6@users.noreply.github.com>
@orshih6
orshih6 requested a review from a team as a code owner November 9, 2026 01:42
Copilot AI auto review requested due to automatic review settings November 9, 2026 01:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Explicitly empty boolean environment variables bypass validation and can start the server with read-only or lockdown protections disabled.

2 open issues
What changed in this PR

Adds boolean environment-value validation to the GitHub MCP Server CLI, addressing the silent disabling of safety settings described in #3747.

Changes:

  • Validates boolean settings during startup for stdio, http, and list-scopes.
  • Adds table-driven tests for valid, invalid, and unset environment values.
  • Documents accepted boolean spellings and startup errors.
File Description
docs/​server-configuration.md Documents accepted boolean environment values.
cmd/​github-mcp-server/​main.go Adds validation to stdio and HTTP startup.
cmd/​github-mcp-server/​main_test.go Tests read-only and lockdown environment parsing.
cmd/​github-mcp-server/​list_scopes.go Validates read-only before listing scopes.
cmd/​github-mcp-server/​helpers.go Defines boolean keys and shared validation logic.

Review effort: Max (auto)

Comment thread cmd/github-mcp-server/helpers.go Resolved
Comment thread cmd/github-mcp-server/main_test.go Resolved
…ed values

Signed-off-by: Бат-Орших <34618353+orshih6@users.noreply.github.com>
@orshih6

orshih6 commented Nov 9, 2026

Copy link
Copy Markdown
Author

@copilot good catches, both fixed. An empty bool env var like GITHUB_READ_ONLY= is now rejected at startup. A flag passed explicitly (e.g. --read-only=false) still overrides it, so validateBoolSettings now takes the command's flag set to check that. The test now clears every checked variable up front and restores them at cleanup. It also gained cases for an empty value and for a flag overriding an empty env var.

@SoulmatelynchVFX SoulmatelynchVFX left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review 草稿 · github/github-mcp-server #3750

  • PR:Reject invalid boolean values for GITHUB_READ_ONLY and other bool env vars(orshih6 · OPEN · 2026-11-09T01:42Z)
  • 提交方式:gh pr review 3750 --repo github/github-mcp-server --comment --body-file <正文>
  • 状态:已备未发,等用户确认
  • 说明:本条按 §6.9.6 写,只含可验证信息,不含空 suggestion,不对当前修复作全称判断。

复核依据(读 cmd/github-mcp-server/helpers.go 新增函数 + list_scopes.go 调用点)

  1. 空值路径:os.LookupEnv 返回 present=true、value="" 时不 continue,落到 strconv.ParseBool("") → 返回错误。注释里写明这是有意为之("a present-but-empty variable is rejected too")。
  2. 容器习惯写法:docker run -e GITHUB_READ_ONLY ...(不带 =value)会把该变量设为空字符串而非未设置;当前 viper 把空值当未设置、read-only 静默关闭,本 PR 之后同样写法会直接 fatal。
  3. 错误文案:strconv.ParseBool 实际接受 1 t T TRUE true True 0 f F FALSE false False,而报错里只列了 1, t, true, 0, f, false。

正文

Read validateBoolSettings in cmd/github-mcp-server/helpers.go and the call site in list_scopes.go. Two things I could verify locally, both about the empty-value branch rather than the parsing itself.

The branch that rejects present && value == "" is a behaviour change for container users. docker run -e GITHUB_READ_ONLY ... (no =value) sets the variable to an empty string, not unset, and viper currently treats that as unset so read-only stays off. After this change the same invocation exits with an error instead of starting with read-only disabled. If failing closed is the intent, that is defensible — but it is a startup failure for setups that work today, so it may deserve a line in the release note or an explicit test case (GITHUB_READ_ONLY= with an empty value) so the change is visible.

Second, the error message lists 1, t, true, 0, f, false, while strconv.ParseBool also accepts T, TRUE, True, F, FALSE, False. Someone who writes GITHUB_LOCKDOWN_MODE=True gets no error, but the message implies they should have used lowercase.

I did not check the other boolSettings keys against the actual flag definitions, so I am not claiming the list is complete or that every key is reachable from an env var.

AI-assisted review (Claude); the checks above were run locally against the PR branch.

…he empty-value change

Signed-off-by: Бат-Орших <34618353+orshih6@users.noreply.github.com>
@orshih6

orshih6 commented Nov 9, 2026

Copy link
Copy Markdown
Author

@SoulmatelynchVFX thanks for checking this. The error message now lists every value ParseBool accepts (1, t, T, true, TRUE, True, 0, f, F, false, FALSE, False). The test now checks that, and it also covers T/True/F/FALSE/False. There's already an explicit empty-value case: GITHUB_READ_ONLY= and GITHUB_LOCKDOWN_MODE= are expected to error, and an explicit flag still overrides an empty env var. To make the behaviour change visible, I added a sentence to the boolean env var note in docs/server-configuration.md. It says a variable that is set but empty now stops startup, where it used to be treated as unset, and the PR description calls it out too. One small correction on the docker example: as far as I know, docker run -e GITHUB_READ_ONLY without = passes the host's value through and leaves the variable unset if the host doesn't have it, so the case that changes is -e GITHUB_READ_ONLY=. That's the one the docs mention. Failing closed is intentional here, since read-only is the safety setting.

Signed-off-by: Бат-Орших <34618353+orshih6@users.noreply.github.com>
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.

GITHUB_READ_ONLY=yes (or on) silently leaves read-only mode off

3 participants