feat(governance): add custom properties tools - #2992
Conversation
There was a problem hiding this comment.
Pull request overview
Adds six custom-property tools to the governance toolset for repository values and organization/enterprise definitions.
Changes:
- Adds read and write handlers with level-specific scopes.
- Adds unit tests and tool-schema snapshots.
- Updates generated governance documentation.
Show a summary per file
| File | Description |
|---|---|
README.md |
Documents the new tools. |
pkg/github/tools.go |
Registers tools and updates metadata. |
pkg/github/custom_properties.go |
Implements custom-property tools and schemas. |
pkg/github/custom_properties_test.go |
Tests handlers and schemas. |
pkg/github/__toolsnaps__/get_repository_custom_properties.snap |
Snapshots repository read schema. |
pkg/github/__toolsnaps__/get_organization_custom_properties.snap |
Snapshots organization read schema. |
pkg/github/__toolsnaps__/get_enterprise_custom_properties.snap |
Snapshots enterprise read schema. |
pkg/github/__toolsnaps__/create_or_update_repository_custom_properties.snap |
Snapshots repository write schema. |
pkg/github/__toolsnaps__/create_or_update_organization_custom_properties.snap |
Snapshots organization write schema. |
pkg/github/__toolsnaps__/create_or_update_enterprise_custom_properties.snap |
Snapshots enterprise write schema. |
docs/remote-server.md |
Updates remote governance documentation. |
Review details
- Files reviewed: 11/11 changed files
- Comments generated: 2
- Review effort level: Balanced
53de049 to
f340ea4
Compare
|
👋 Heads up: #2991 (this PR's base) was rebased onto current This PR's custom-properties functionality is not superseded by that change — it's a separate API surface and remains a valid follow-on layer. Two things to do before it can merge cleanly though:
Leaving this open since the functionality itself is still needed. |
8e78920 to
fe0ece5
Compare
484991c to
718451c
Compare
1c811cc to
1b9a80e
Compare
718451c to
b11fcb2
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unknown property fields can be silently discarded, causing unintended governance definitions.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Balanced
Findings: 1
New issues introduced by this change (1)
| Severity | Finding |
|---|---|
pkg/github/custom_properties.go — Unknown item keys are currently allowed by the schema and then silently discarded by… |
Issues resolved since last review (2)
| Severity | Finding |
|---|---|
pkg/github/custom_properties.go — The description limits default_value to a string or string array, but the schema has no type… View resolved comment |
|
pkg/github/custom_properties.go — value is optional in this schema, but go-github's CustomPropertyValue.Value is serialized… View resolved comment |
b11fcb2 to
528fcc7
Compare
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Level-incompatible property fields are accepted and then silently discarded.
Review tier: Balanced
Findings: None
Issues resolved since last review (1)
| Severity | Finding |
|---|---|
pkg/github/custom_properties.go — Unknown item keys are currently allowed by the schema and then silently discarded by… View resolved comment |
Suppressed comments (1)
pkg/github/custom_properties.go:283
- The combined item schema accepts fields from both payload shapes at every level, but
parseCustomPropertieslater unmarshals into a level-specific go-github struct, soencoding/jsonsilently drops fields from the other shape. For example, an organization item containingproperty_name,value_type, andvaluesucceeds whilevaluenever reaches GitHub; repository items similarly discard definition fields. Reject fields that are invalid for the selected level (or use level-specificoneOfschemas) so accepted input is not silently ignored.
// customPropertyItemSchema combines repository values with organization and enterprise definitions.
func customPropertyItemSchema() *jsonschema.Schema {
return &jsonschema.Schema{
Type: "object",
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
528fcc7 to
bfc8eb5
Compare
bfc8eb5 to
8716efe
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The write contract does not disclose replacement semantics that can silently reset governance settings.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Balanced
Findings: 1
New issues introduced by this change (1)
| Severity | Finding |
|---|---|
pkg/github/custom_properties.go — For organization and enterprise definitions, this bulk PATCH replaces an existing definition:… |
3bea8e2 to
b89714a
Compare
…challenge Add custom properties support to the non-default governance toolset, completing the second half of the rulesets + custom properties work requested in #820. Rather than porting the original six single-level tools verbatim, this consolidates them into two level-parameterized tools: - custom_properties_read (level: repository | organization | enterprise) - custom_properties_write (level: repository | organization | enterprise) The `level` argument dispatches to the correct GitHub API. Repository level reads and writes property VALUES (property_name + value), while organization and enterprise levels read and write property DEFINITIONS/schema (value_type, required, allowed_values, default_value, description, values_editable_by). This distinction is documented in the tool and field descriptions. Both tools reuse the shared governanceReadScopeAccess/governanceWriteScopeAccess helpers (renamed from the ruleset-specific names) so rulesets and custom properties present one consistent, exhaustive scope-challenge policy that up-scopes based on the requested level. Co-authored-by: Patrick Knight <patrick-knight@github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1e886867-a922-419a-b02c-ac643716aea8
Co-authored-by: Patrick Knight <patrick-knight@github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1e886867-a922-419a-b02c-ac643716aea8
Co-authored-by: Patrick Knight <patrick-knight@github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1e886867-a922-419a-b02c-ac643716aea8
Co-authored-by: Patrick Knight <patrick-knight@github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1e886867-a922-419a-b02c-ac643716aea8
Co-authored-by: Patrick Knight <patrick-knight@github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1e886867-a922-419a-b02c-ac643716aea8
8716efe to
7c7720e
Compare
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The write API does not disclose destructive replacement semantics for omitted definition fields.
Review tier: Balanced
Findings: 1
Pre-existing issues (1)
| Severity | Finding |
|---|---|
pkg/github/custom_properties.go — For organization and enterprise definitions, this bulk PATCH replaces an existing definition:… View comment |
Suppressed comments (1)
pkg/github/custom_properties.go:179
- For organization and enterprise updates, GitHub replaces an existing definition and resets every omitted optional field to its default. Describing these fields only as optional makes a partial-looking update capable of silently clearing
required,default_value,description, andallowed_values, and resettingvalues_editable_by. Please either document that each item must contain the complete desired definition or merge omitted fields with the current definition before PATCHing.
Description: "The custom properties to create or update. At the repository level each item assigns a value ('property_name' and 'value'); at the organization and enterprise levels each item defines the schema ('property_name' and 'value_type', plus optional definition fields).",
Co-authored-by: Patrick Knight <patrick-knight@github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1e886867-a922-419a-b02c-ac643716aea8
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The implementation, scope dispatch, validation, tests, snapshots, and generated documentation are consistent and complete.
Review tier: Balanced
Findings: None
Issues resolved since last review (1)
| Severity | Finding |
|---|---|
pkg/github/custom_properties.go — For organization and enterprise definitions, this bulk PATCH replaces an existing definition:… View resolved comment |


Governance toolset — Custom Properties (PR 2 of 2)
Adds the second half of the non-default
governancetoolset: GitHub custom properties at the repository, organization, and enterprise levels.Supersedes the very stale #821 (re: #820), replayed onto the current codebase (modelcontextprotocol/go-sdk, go-github v89) and consolidated to fit today's tool surface.
Tools (2)
Rather than porting #821's six single-level tools verbatim, this consolidates them into two
level-parameterized tools, mirroring the ruleset tools in #2991:levelvaluescustom_properties_readrepository/organization/enterprisecustom_properties_writerepository/organization/enterpriseValues vs. definitions
The
levelargument dispatches to the correct GitHub API, and the semantics differ by level (documented in the tool + field descriptions):repositoryreads/writes property values (property_name+value) — this is the inventory-ID / cost-centre source-of-truth use case customers asked for.organization/enterpriseread/write property definitions / schema (value_type,required,allowed_values,default_value,description,values_editable_by).Scope challenge
Both tools reuse the shared
governanceReadScopeAccess/governanceWriteScopeAccesshelpers introduced in #2991 (renamed from the ruleset-specific names). They use aDynamicChallengekeyed onlevel, so a repository-level call needs only repo scope and org/enterprise calls up-scope from there — one consistent, exhaustive policy across both rulesets and custom properties.Size
+812 / −20 across 9 files (363 lines of tool logic, 262 of tests, plus toolsnaps + regenerated README).
Verified:
script/lint(0 issues),script/test(race),script/generate-docsall green.Co-authored with @patrick-knight, original author of #821.
Closes #820