Skip to content

fix(schema): OpenAPI 3.1 bump + schema fixes#1025

Open
tdabasinskas wants to merge 7 commits into
github-community-projects:main-enterprisefrom
datolabs-io:fix/schema-nullable-rewrite
Open

fix(schema): OpenAPI 3.1 bump + schema fixes#1025
tdabasinskas wants to merge 7 commits into
github-community-projects:main-enterprisefrom
datolabs-io:fix/schema-nullable-rewrite

Conversation

@tdabasinskas

@tdabasinskas tdabasinskas commented Jul 11, 2026

Copy link
Copy Markdown

Fixes #1024.

Three related fixes to the config schemas.

1. Consume GitHub's OpenAPI 3.1 description so nullable API fields validate

The generated schemas declare draft 2020-12 but were built from GitHub's OpenAPI 3.0 description, whose nullable: true markers are meaningless in that dialect. Fields the API documents as null-able rejected null under any compliant validator:

branches:
  - name: main
    protection:
      required_status_checks: null   # API: "Set to null to disable" — schema: rejected
      enforce_admins: true
      restrictions: null

The 18 spec $refs in schema/*.json now point at descriptions-next/, GitHub's OpenAPI 3.1 build of the same pinned snapshot date, and the resolver in script/build-schema serves the pre-dereferenced spec for exactly that URL. OpenAPI 3.1 is native JSON Schema 2020-12: null-ability arrives as type: [X, "null"] unions, so the output is dialect-true with no post-processing. (Bonus: the 3.1 spec also adds User to the ruleset bypass actor_type enum.)

2. Allow protection: null, safe-settings' own delete-branch-protection syntax

The branches plugin deletes branch protection when the config says protection: null (isEmpty in lib/plugins/branches.js; there's an upstream unit test for exactly this shape), but the schema modeled protection as the API's PUT body only, which is type: object. The property is now an anyOf of { "type": "null" } and the existing PUT-body reference, in all three schemas. Object values still validate against the full PUT body.

3. Validate rulesets in suborg and repo configs

Suborg and repo override files can configure rulesets: (they feed the rulesets plugin at repo scope via childPluginsList), but schema/repos.json and schema/suborgs.json had no rulesets property, so anything under that key passed validation silently:

# passed schema validation before this PR
rulesets:
  - enforcement: definitely-not-a-valid-value
    bypass_actors:
      - actor_type: Wizard

Both files actually already contained an unused RulesetSettings definition; it's now wired to a rulesets property, and pointed at the repo-level POST /repos/{owner}/{repo}/rulesets body instead of the org-level one it referenced (repo rulesets have no repository_name/repository_property condition targeting). The config above now fails with three precise errors; realistic per-repo ruleset configs validate.

Not included: actor_type: EnterpriseOwner, which the API returns for enterprise-owned orgs but which is missing from GitHub's own OpenAPI spec (reported at github/rest-api-description#); it will flow in with a future spec pin bump.

Regenerated artifacts

schema/dereferenced/*.json are rebuilt with npm run build:schema only — no hand edits. Notes for reviewing the diff: rebuilding at current HEAD without any changes already produces a ~264-line diff (the committed artifacts were stale); the anyOf wrapper re-indents the whole protection subtree (git diff -w shows the real change is +72 lines); the rulesets addition inlines the repo-ruleset subschema. Regeneration is deterministic: running the build twice produces no further changes.

Tests

New test/unit/schema.test.js: no nullable keyword survives anywhere; required_status_checks, enforce_admins, and restrictions accept null; protection: null is accepted by all three schemas; suborg/repo rulesets validate against the repo-level shape (required name+enforcement, no org-only conditions, User in the bypass enum).

The generated schemas declare JSON Schema draft 2020-12, where OpenAPI 3.0's `nullable` keyword does not exist. The build now consumes GitHub's OpenAPI 3.1 description, which models null-ability as `type: [X, 'null']` unions instead.

Update the schema build script to reference the `descriptions-next` directory containing the OpenAPI 3.1 spec. Add comprehensive test coverage to ensure no `nullable` keywords survive in the dereferenced output and verify that required-but-nullable fields use proper type unions.
Copilot AI review requested due to automatic review settings July 11, 2026 10:37

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.

Pull request overview

Updates schema generation to consume GitHub’s OpenAPI 3.1 (“descriptions-next”) snapshot so nullability is expressed in JSON Schema 2020-12 terms (e.g., type: [..., "null"]) instead of OpenAPI 3.0’s nullable keyword, and regenerates dereferenced artifacts accordingly.

Changes:

  • Point schema/*.json external $refs at descriptions-next/ (OpenAPI 3.1) instead of descriptions/ (OpenAPI 3.0).
  • Update script/build-schema’s resolver pattern to read from descriptions-next.
  • Add a unit test to ensure generated dereferenced schemas contain no nullable keywords and that branch protection fields allow null.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/unit/schema.test.js Adds regression tests to prevent nullable leakage and verify nullability for key branch protection fields.
script/build-schema Updates the resolver matching to align dereferencing with the OpenAPI 3.1 source URLs.
schema/settings.json Switches GitHub spec $refs to descriptions-next URLs.
schema/repos.json Switches GitHub spec $refs to descriptions-next URLs.
schema/suborgs.json Switches GitHub spec $refs to descriptions-next URLs.
schema/dereferenced/settings.json Regenerated dereferenced schema reflecting OpenAPI 3.1 null unions and upstream drift.
schema/dereferenced/repos.json Regenerated dereferenced schema reflecting OpenAPI 3.1 null unions and upstream drift.
schema/dereferenced/suborgs.json Regenerated dereferenced schema reflecting OpenAPI 3.1 null unions and upstream drift.

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

Comment thread test/unit/schema.test.js Outdated
Comment thread script/build-schema
The schema now uses `anyOf` to allow `protection: null` as a safe-settings semantic for deleting branch protection. Updated tests to:
- Navigate the `anyOf` structure to find the object variant
- Verify that `protection: null` is allowed in all schemas with branches

This ensures tests correctly validate the schema's support for the delete-branch-protection semantic, which differs from the GitHub API's PUT body structure.
The previous regex-based canRead check could potentially match unintended URLs. Replace with exact URL comparison to ensure the resolver only serves the pre-dereferenced spec for the exact URL pinned in schema files.

Also expand test coverage to verify enforce_admins nullable handling alongside existing required_status_checks check.
@tdabasinskas tdabasinskas requested a review from Copilot July 11, 2026 10:48
@tdabasinskas tdabasinskas changed the title fix(schema): consume GitHub's OpenAPI 3.1 description so nullable fields validate fix(schema): OpenAPI 3.1 bump + schema fixes Jul 11, 2026
The `rulesets` property in both `repos.json` and `suborgs.json` was incorrectly referencing the org-level ruleset API schema. Since these files feed the rulesets plugin at repository scope (via `childPluginsList` in `lib/settings.js`), they must validate against the repo-level API shape instead.

This ensures:
- Org-only condition targeting (like `repository_name`) does not leak into repo-level validation
- Actor types like `User` are properly available at repo scope
- Schema validation matches the actual API endpoint being called

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.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated no new comments.

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.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated 3 comments.

Comment thread schema/settings.json
Comment thread schema/suborgs.json
Comment thread schema/repos.json
Replace `type: null` with `enum: [null, {}, [], false]` to match the actual empty value semantics used by the branches plugin. The plugin's `isEmpty` function treats null, empty objects, empty arrays, and false as deletion signals, but the schema only validated null.

Update test to verify all four empty values are accepted in the schema, aligning validation with runtime behavior.

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.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated 4 comments.

Comment thread test/unit/schema.test.js Outdated
Comment thread test/unit/schema.test.js Outdated
Comment thread test/unit/schema.test.js Outdated
Comment thread test/unit/schema.test.js Outdated
Add explicit `utf8` encoding parameter to all `fs.readFileSync()` calls in schema tests to ensure consistent text file handling across different platforms and Node.js versions.

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.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated 2 comments.

Comment thread test/unit/schema.test.js
Comment thread test/unit/schema.test.js
Replace exact array equality checks with order-independent assertions using `toHaveLength` and `arrayContaining` matchers. This prevents test brittleness when schema property ordering changes during generation or serialization.

Affected assertions:
- `ruleset.required` array membership
- `protection.anyOf` enum values

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.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated 1 comment.

Comment thread script/build-schema
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.

Generated schemas keep OpenAPI nullable, so required-but-nullable fields reject null

2 participants