Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERROR: For 'anyOf/1', {"strict"=>true, "contexts"=>[], "checks"=>[]} is not a null. #12

Open
NiccoloFei opened this issue Nov 24, 2021 · 5 comments

Comments

@NiccoloFei
Copy link

Hello,

Since last week approximately the script started failing with the following error:

npm WARN exec The following package was not found and will be installed: @octoherd/script-sync-branch-protections

Running @octoherd/cli v3.4.4 (@octoherd/octokit v2.3.1, Node.js: v16.13.0, linux x64)
 INFO  Loading repositories ...
.
 INFO  Running on <myorg>/<my_repo> ...
 INFO  branch protection settings loaded from <myorg>/<my_template_repo> {"required_status_checks":{"strict":true,"contexts":[],"checks":[]},"enforce_admins":true,"required_pull_request_reviews":{"dismiss_stale_reviews":false,"require_code_owner_reviews":true,"required_approving_review_count":2},"restrictions":null,"required_signatures":false,"required_linear_histor … }
 ERROR  HttpError: Invalid request.

No subschema in "anyOf" matched.
More than one subschema in "oneOf" matched.
Not all subschemas of "allOf" matched.
For 'anyOf/1', {"strict"=>true, "contexts"=>[], "checks"=>[]} is not a null.
    at /home/runner/.npm/_npx/9c37c62cde30630c/node_modules/@octokit/request/dist-node/index.js:86:21
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Job.doExecute (/home/runner/.npm/_npx/9c37c62cde30630c/node_modules/bottleneck/light.js:405:18) {"name":"HttpError","status":422,"response":{"url":"https://api.github.com/repos/<myorg>/<my_repo>/branches/main/protection","status":422,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateL … }

This is the JSON of the template repo returned by the Github API (the one from the destination repository looks the same):

{
  "url": "https://api.github.com/repos/<myorg>/<my_template_repo>/branches/main/protection",
  "required_status_checks": {
    "url": "https://api.github.com/repos/<myorg>/<my_template_repo>/branches/main/protection/required_status_checks",
    "strict": true,
    "contexts": [],
    "contexts_url": "https://api.github.com/repos/<myorg>/<my_template_repo>/branches/main/protection/required_status_checks/contexts",
    "checks": []
  },
  "required_pull_request_reviews": {
    "url": "https://api.github.com/repos/<myorg>/<my_template_repo>/branches/main/protection/required_pull_request_reviews",
    "dismiss_stale_reviews": false,
    "require_code_owner_reviews": true,
    "required_approving_review_count": 2
  },
  "required_signatures": {
    "url": "https://api.github.com/repos/<myorg>/<my_template_repo>/branches/main/protection/required_signatures",
    "enabled": false
  },
  "enforce_admins": {
    "url": "https://api.github.com/repos/<myorg>/<my_template_repo>/branches/main/protection/enforce_admins",
    "enabled": true
  },
  "required_linear_history": {
    "enabled": true
  },
  "allow_force_pushes": {
    "enabled": false
  },
  "allow_deletions": {
    "enabled": false
  },
  "required_conversation_resolution": {
    "enabled": false
  }
}
@gr2m
Copy link
Member

gr2m commented Nov 24, 2021

That sounds like there was a change with GitHub's API. I don't have the time to dive into this myself right now I'm afraid.

Can you run the the script with --octoherd-debug and see if you get some extra information? Octoherd should also write logs to a temporary file, I think it logs out the location of that file in the beginning. In there you should get more details as well

@NiccoloFei
Copy link
Author

NiccoloFei commented Dec 3, 2021

In the above output --octoherd-debug was already set. The command executed was:

npx @octoherd/script-sync-branch-protections --template EnterpriseDB/my-template-repo -T *** -R EnterpriseDB/my-destination-repo --octoherd-bypass-confirms --octoherd-debug

The content of the temporary file is attached here: octoherd_failure.ndjson.log

It seems like the field giving issues is required_status_checks.checks, which in my case (when not empty) looks like this:

"checks": [
  {
    "context": "test 1",
    "app_id": null
  },
  {
    "context": "test 2",
    "app_id": null
  },
]

@gr2m
Copy link
Member

gr2m commented Dec 3, 2021

Thanks Niccolò!

For reference, the relevant error log is this one

{
  "repository": {
    "id": 370718979,
    "owner": {
      "login": "EnterpriseDB",
      "id": 7386129,
      "node_id": "MDEyOk9yZ2FuaXphdGlvbjczODYxMjk=",
      "avatar_url": "https://avatars.githubusercontent.com/u/7386129?v=4",
      "gravatar_id": "",
      "url": "https://api.github.com/users/EnterpriseDB",
      "html_url": "https://github.com/EnterpriseDB",
      "followers_url": "https://api.github.com/users/EnterpriseDB/followers",
      "following_url": "https://api.github.com/users/EnterpriseDB/following{/other_user}",
      "gists_url": "https://api.github.com/users/EnterpriseDB/gists{/gist_id}",
      "starred_url": "https://api.github.com/users/EnterpriseDB/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/EnterpriseDB/subscriptions",
      "organizations_url": "https://api.github.com/users/EnterpriseDB/orgs",
      "repos_url": "https://api.github.com/users/EnterpriseDB/repos",
      "events_url": "https://api.github.com/users/EnterpriseDB/events{/privacy}",
      "received_events_url": "https://api.github.com/users/EnterpriseDB/received_events",
      "type": "Organization",
      "site_admin": false
    },
    "name": "my-destination-repo"
  },
  "msg": "HttpError: Invalid request.\n\nNo subschema in \"anyOf\" matched.\nMore than one subschema in \"oneOf\" matched.\nNot all subschemas of \"allOf\" matched.\nFor 'anyOf/1', {\"strict\"=>true, \"contexts\"=>[], \"checks\"=>[]} is not a null.\n    at /home/runner/.npm/_npx/9c37c62cde30630c/node_modules/@octokit/request/dist-node/index.js:86:21\n    at processTicksAndRejections (node:internal/process/task_queues:96:5)\n    at async Job.doExecute (/home/runner/.npm/_npx/9c37c62cde30630c/node_modules/bottleneck/light.js:405:18)",
  "name": "HttpError",
  "status": 422,
  "response": {
    "url": "https://api.github.com/repos/EnterpriseDB/my-destination-repo/branches/main/protection",
    "status": 422,
    "headers": {
      "access-control-allow-origin": "*",
      "access-control-expose-headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset",
      "connection": "close",
      "content-length": "333",
      "content-security-policy": "default-src 'none'",
      "content-type": "application/json; charset=utf-8",
      "date": "Wed, 01 Dec 2021 10:59:45 GMT",
      "referrer-policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
      "server": "GitHub.com",
      "strict-transport-security": "max-age=31536000; includeSubdomains; preload",
      "vary": "Accept-Encoding, Accept, X-Requested-With",
      "x-accepted-oauth-scopes": "",
      "x-content-type-options": "nosniff",
      "x-frame-options": "deny",
      "x-github-media-type": "github.v3; format=json",
      "x-github-request-id": "0404:27AC:70633E:DAB170:61A755A1",
      "x-oauth-scopes": "delete:packages, read:org, repo, workflow, write:packages",
      "x-ratelimit-limit": "5000",
      "x-ratelimit-remaining": "4994",
      "x-ratelimit-reset": "1638357051",
      "x-ratelimit-resource": "core",
      "x-ratelimit-used": "6",
      "x-xss-protection": "0"
    },
    "data": {
      "message": "Invalid request.\n\nNo subschema in \"anyOf\" matched.\nMore than one subschema in \"oneOf\" matched.\nNot all subschemas of \"allOf\" matched.\nFor 'anyOf/1', {\"strict\"=>true, \"contexts\"=>[], \"checks\"=>[]} is not a null.",
      "documentation_url": "https://docs.github.com/rest/reference/repos#update-branch-protection"
    }
  },
  "request": {
    "method": "PUT",
    "url": "https://api.github.com/repos/EnterpriseDB/my-destination-repo/branches/main/protection",
    "headers": {
      "accept": "application/vnd.github.v3+json",
      "user-agent": "octoherd-cli/3.4.5 octoherd-cli/2.3.1 octokit-core.js/3.5.1 Node.js/16.13.0 (linux; x64)",
      "authorization": "token [REDACTED]",
      "content-type": "application/json; charset=utf-8"
    },
    "body": "{\"required_status_checks\":{\"strict\":true,\"contexts\":[],\"checks\":[]},\"enforce_admins\":true,\"required_pull_request_reviews\":{\"dismiss_stale_reviews\":false,\"require_code_owner_reviews\":true,\"required_approving_review_count\":2},\"restrictions\":null,\"required_signatures\":false,\"required_linear_history\":true,\"allow_force_pushes\":false,\"allow_deletions\":false,\"required_conversation_resolution\":false,\"msg\":\"branch protection settings loaded from EnterpriseDB/my-template-repo\"}",
    "request": {}
  },
  "level": "error",
  "time": 1638356385305
}

GitHub does not like the request body for some reason:

{
  "required_status_checks": { "strict": true, "contexts": [], "checks": [] },
  "enforce_admins": true,
  "required_pull_request_reviews": {
    "dismiss_stale_reviews": false,
    "require_code_owner_reviews": true,
    "required_approving_review_count": 2
  },
  "restrictions": null,
  "required_signatures": false,
  "required_linear_history": true,
  "allow_force_pushes": false,
  "allow_deletions": false,
  "required_conversation_resolution": false,
  "msg": "branch protection settings loaded from EnterpriseDB/my-template-repo"
}

The relevant OpenAPI spec from https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.yaml

      summary: Update branch protection
      operationId: repos/update-branch-protection
      # ...
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                required_status_checks:
                  type: object
                  description: Require status checks to pass before merging. Set to
                    `null` to disable.
                  nullable: true
                  properties:
                    strict:
                      type: boolean
                      description: Require branches to be up to date before merging.
                    contexts:
                      type: array
                      deprecated: true
                      description: "**Deprecated**: The list of status checks to require
                        in order to merge into this branch. If any of these checks
                        have recently been set by a particular GitHub App, they will
                        be required to come from that app in future for the branch
                        to merge. Use `checks` instead of `contexts` for more fine-grained
                        control.\n"
                      items:
                        type: string
                    checks:
                      type: array
                      description: The list of status checks to require in order to
                        merge into this branch.
                      items:
                        type: object
                        required:
                        - context
                        properties:
                          context:
                            type: string
                            description: The name of the required check
                          app_id:
                            type: integer
                            description: The ID of the GitHub App that must provide
                              this check. Omit this field to automatically select
                              the GitHub App that has recently provided this check,
                              or any app if it was not set by a GitHub App.
                  required:
                  - strict
                  - contexts
                enforce_admins:
                  type: boolean
                  description: Enforce all configured restrictions for administrators.
                    Set to `true` to enforce required status checks for repository
                    administrators. Set to `null` to disable.
                  nullable: true
                required_pull_request_reviews:
                  type: object
                  description: Require at least one approving review on a pull request,
                    before merging. Set to `null` to disable.
                  nullable: true
                  properties:
                    dismissal_restrictions:
                      type: object
                      description: Specify which users and teams can dismiss pull
                        request reviews. Pass an empty `dismissal_restrictions` object
                        to disable. User and team `dismissal_restrictions` are only
                        available for organization-owned repositories. Omit this parameter
                        for personal repositories.
                      properties:
                        users:
                          type: array
                          description: The list of user `login`s with dismissal access
                          items:
                            type: string
                        teams:
                          type: array
                          description: The list of team `slug`s with dismissal access
                          items:
                            type: string
                    dismiss_stale_reviews:
                      type: boolean
                      description: Set to `true` if you want to automatically dismiss
                        approving reviews when someone pushes a new commit.
                    require_code_owner_reviews:
                      type: boolean
                      description: Blocks merging pull requests until [code owners](https://help.github.com/articles/about-code-owners/)
                        review them.
                    required_approving_review_count:
                      type: integer
                      description: Specify the number of reviewers required to approve
                        pull requests. Use a number between 1 and 6.
                restrictions:
                  type: object
                  description: Restrict who can push to the protected branch. User,
                    app, and team `restrictions` are only available for organization-owned
                    repositories. Set to `null` to disable.
                  nullable: true
                  properties:
                    users:
                      type: array
                      description: The list of user `login`s with push access
                      items:
                        type: string
                    teams:
                      type: array
                      description: The list of team `slug`s with push access
                      items:
                        type: string
                    apps:
                      type: array
                      description: The list of app `slug`s with push access
                      items:
                        type: string
                  required:
                  - users
                  - teams
                required_linear_history:
                  type: boolean
                  description: 'Enforces a linear commit Git history, which prevents
                    anyone from pushing merge commits to a branch. Set to `true` to
                    enforce a linear commit history. Set to `false` to disable a linear
                    commit Git history. Your repository must allow squash merging
                    or rebase merging before you can enable a linear commit history.
                    Default: `false`. For more information, see "[Requiring a linear
                    commit history](https://help.github.com/github/administering-a-repository/requiring-a-linear-commit-history)"
                    in the GitHub Help documentation.'
                allow_force_pushes:
                  type: boolean
                  description: 'Permits force pushes to the protected branch by anyone
                    with write access to the repository. Set to `true` to allow force
                    pushes. Set to `false` or `null` to block force pushes. Default:
                    `false`. For more information, see "[Enabling force pushes to
                    a protected branch](https://help.github.com/en/github/administering-a-repository/enabling-force-pushes-to-a-protected-branch)"
                    in the GitHub Help documentation."'
                  nullable: true
                allow_deletions:
                  type: boolean
                  description: 'Allows deletion of the protected branch by anyone
                    with write access to the repository. Set to `false` to prevent
                    deletion of the protected branch. Default: `false`. For more information,
                    see "[Enabling force pushes to a protected branch](https://help.github.com/en/github/administering-a-repository/enabling-force-pushes-to-a-protected-branch)"
                    in the GitHub Help documentation.'
                required_conversation_resolution:
                  type: boolean
                  description: 'Requires all conversations on code to be resolved
                    before a pull request can be merged into a branch that matches
                    this rule. Set to `false` to disable. Default: `false`.'
              required:
              - required_status_checks
              - enforce_admins
              - required_pull_request_reviews
              - restrictions

It seems like the field giving issues is required_status_checks.checks, which in my case (when not empty) looks like this:

"checks": [
  {
    "context": "test 1",
    "app_id": null
  },
  {
    "context": "test 2",
    "app_id": null
  },
]

based on the spec, app_id must be a number. I assume when we load the configuration it returns null, so these two are incompatible.

Could you try to see if you can add code to normalize it? Basically remove the app_id property if it is set to null in the response from the template repository?

@NiccoloFei
Copy link
Author

NiccoloFei commented Feb 14, 2022

@gr2m Apologies for the late reply, I've been able to work around this issue by deleting the required_status_checks.contexts field:

diff --git a/script.js b/script.js
index b68ca09..00a3886 100644
--- a/script.js
+++ b/script.js
@@ -88,6 +88,8 @@ export async function script(octokit, repository, options) {
       }
     }

+    delete templateBranchProtectionSettings.required_status_checks.contexts
+
     await octokit.request(
       "PUT /repos/{owner}/{repo}/branches/{branch}/protection",
       {

It seems that contexts is both deprecated in favor of checks and required at the same time. Removing it and leaving only checks solves the issue and also allows to synchronise the ID of GitHub Apps allowed for each status check.

@gr2m
Copy link
Member

gr2m commented Apr 20, 2022

Would you like to send a pull request, ideally with a test?

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

No branches or pull requests

2 participants