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

allow non target access actors to check, compose, delete and publish schemas #6449

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

n1ru4l
Copy link
Contributor

@n1ru4l n1ru4l commented Jan 30, 2025

Background

We will soon introduce a new access token not bound to a single target. When we ship that change, users must specify which target they want to act on for those new access tokens.

Description

This change adds passing an optional target slug selector to the Mutation.schemaCheck, Mutation.schemaCompose, Mutation.schemaDelete, Mutation.schemaPublish, Mutation.createAppDeployment, Mutation.addDocumentsToAppDeployment and Mutation.activateAppDeployment fields input types.

The selector is used to resolve the affected target instead of the target bound to the registry access token (if provided).
If the target resolved by the selector does not match the permissions of the registry access token, a permission error is raised.


The main purpose of this change is to encourage people to pass a --target flag via the CLI, so it is later on easier to make it mandatory. The CLI flag is also introduced within this pull request.

hive schema:publish --target the-guild/graphql-hive/production ./my-schema.graphql

Checklist

  • Input validation
  • Output encoding
  • Authentication management
  • Session management
  • Access control
  • Cryptographic practices
  • Error handling and logging
  • Data protection
  • Communication security
  • System configuration
  • Database security
  • File management
  • Memory management
  • Testing

@n1ru4l n1ru4l force-pushed the feat-cli-fields-selector branch from f4a34ae to 8e713c9 Compare January 30, 2025 15:25
Copy link
Contributor

github-actions bot commented Jan 30, 2025

🐋 This PR was built and pushed to the following Docker images:

Targets: build

Platforms: linux/amd64

Image Tag: 58e59db9d0c22995111323e922c592fea7a42c63

Docker Bake metadata
{
"app": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/api/health",
          "build-arg:IMAGE_DESCRIPTION": "The app of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/app",
          "build-arg:PORT": "3000",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/app",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/22j04iocxh6r7rz4y2py9k0r7",
  "containerimage.config.digest": "sha256:1848de29e95480f4f0245af8da6a28f7afcdd270efc96f06e7f21ee8e4f3240b",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:747c12f00d75d243fa0c9d92ba98b2be09998ef651e5a13b63a2904321379a71",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:747c12f00d75d243fa0c9d92ba98b2be09998ef651e5a13b63a2904321379a71",
  "image.name": "ghcr.io/graphql-hive/app:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/app:feat_cli_fields_selector-amd64"
},
"buildx.build.warnings": [
  {
    "vertex": "sha256:82a8b1870c02fe52b00e0e62a940510173c8bc1cb86e785e663d599faa93bf06",
    "level": 1,
    "short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDExKQ==",
    "detail": [
      "TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
    "sourceInfo": {
      "filename": "migrations.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 11
        },
        "end": {
          "line": 11
        }
      }
    ]
  },
  {
    "vertex": "sha256:82a8b1870c02fe52b00e0e62a940510173c8bc1cb86e785e663d599faa93bf06",
    "level": 1,
    "short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDEyKQ==",
    "detail": [
      "TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
    "sourceInfo": {
      "filename": "migrations.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 12
        },
        "end": {
          "line": 12
        }
      }
    ]
  },
  {
    "vertex": "sha256:82a8b1870c02fe52b00e0e62a940510173c8bc1cb86e785e663d599faa93bf06",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9ERVNDUklQVElPTicgKGxpbmUgMTcp",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "migrations.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 17
        },
        "end": {
          "line": 17
        }
      }
    ]
  },
  {
    "vertex": "sha256:1f8acb276113515f60a611e426b73e39b08e1a249f66d9b13fbc5bdffef21597",
    "level": 1,
    "short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIwKQ==",
    "detail": [
      "TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 20
        },
        "end": {
          "line": 20
        }
      }
    ]
  },
  {
    "vertex": "sha256:1f8acb276113515f60a611e426b73e39b08e1a249f66d9b13fbc5bdffef21597",
    "level": 1,
    "short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIyKQ==",
    "detail": [
      "TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 22
        },
        "end": {
          "line": 22
        }
      }
    ]
  },
  {
    "vertex": "sha256:1f8acb276113515f60a611e426b73e39b08e1a249f66d9b13fbc5bdffef21597",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAxMyk=",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 13
        },
        "end": {
          "line": 13
        }
      }
    ]
  },
  {
    "vertex": "sha256:1f8acb276113515f60a611e426b73e39b08e1a249f66d9b13fbc5bdffef21597",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9USVRMRScgKGxpbmUgMTIp",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 12
        },
        "end": {
          "line": 12
        }
      }
    ]
  },
  {
    "vertex": "sha256:1f8acb276113515f60a611e426b73e39b08e1a249f66d9b13fbc5bdffef21597",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9ERVNDUklQVElPTicgKGxpbmUgMTQp",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 14
        },
        "end": {
          "line": 14
        }
      }
    ]
  },
  {
    "vertex": "sha256:1f8acb276113515f60a611e426b73e39b08e1a249f66d9b13fbc5bdffef21597",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAyMSk=",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 21
        },
        "end": {
          "line": 21
        }
      }
    ]
  },
  {
    "vertex": "sha256:1f8acb276113515f60a611e426b73e39b08e1a249f66d9b13fbc5bdffef21597",
    "level": 1,
    "short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIxKQ==",
    "detail": [
      "TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 21
        },
        "end": {
          "line": 21
        }
      }
    ]
  },
  {
    "vertex": "sha256:1f8acb276113515f60a611e426b73e39b08e1a249f66d9b13fbc5bdffef21597",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRQT1JUJyAobGluZSAyMik=",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 22
        },
        "end": {
          "line": 22
        }
      }
    ]
  },
  {
    "vertex": "sha256:82a8b1870c02fe52b00e0e62a940510173c8bc1cb86e785e663d599faa93bf06",
    "level": 1,
    "short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDEwKQ==",
    "detail": [
      "TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
    "sourceInfo": {
      "filename": "migrations.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 10
        },
        "end": {
          "line": 10
        }
      }
    ]
  },
  {
    "vertex": "sha256:82a8b1870c02fe52b00e0e62a940510173c8bc1cb86e785e663d599faa93bf06",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAxMik=",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "migrations.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 12
        },
        "end": {
          "line": 12
        }
      }
    ]
  },
  {
    "vertex": "sha256:82a8b1870c02fe52b00e0e62a940510173c8bc1cb86e785e663d599faa93bf06",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9USVRMRScgKGxpbmUgMTUp",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "migrations.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 15
        },
        "end": {
          "line": 15
        }
      }
    ]
  }
],
"composition-federation-2": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "Federation 2 Composition Service for GraphQL Hive.",
          "build-arg:IMAGE_TITLE": "graphql-hive/composition-federation-2",
          "build-arg:PORT": "3069",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/external-composition",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/pwxdo8bi1qv8olqkdvkwk8uvl",
  "containerimage.config.digest": "sha256:90c1466c8cbbb4c92e579dab1f26e875edb3d49a579821b6083d92708a0e6f85",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:f3b10038961fb63a8c534c146135986049027265ac8b5dd07e4275ec9f5311ba",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:f3b10038961fb63a8c534c146135986049027265ac8b5dd07e4275ec9f5311ba",
  "image.name": "ghcr.io/graphql-hive/composition-federation-2:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/composition-federation-2:feat_cli_fields_selector-amd64"
},
"emails": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The emails service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/emails",
          "build-arg:PORT": "3006",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/emails",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/ut5f35rj171bwb2kvjqvpev0z",
  "containerimage.config.digest": "sha256:8c7d922126a4bb415c74edb7c363443838e20f3f5dbafc940db42643a61cb790",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:98a7aa01750e7054ff7a4824189cb104a272e868a26b5156186de5cfb10d02c8",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:98a7aa01750e7054ff7a4824189cb104a272e868a26b5156186de5cfb10d02c8",
  "image.name": "ghcr.io/graphql-hive/emails:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/emails:feat_cli_fields_selector-amd64"
},
"policy": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The policy service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/policy",
          "build-arg:PORT": "3012",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/policy",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/c8e5gv8bl21wuvirmop0qi9fr",
  "containerimage.config.digest": "sha256:cbb701af7ee786e8446ac9af6d056f89db89e40620fe44187b90fe3fa18be159",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:a9e4ff5ba41a2be3b1cb75398790209a69b7403149bd2ad31194e1f99d84eec6",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:a9e4ff5ba41a2be3b1cb75398790209a69b7403149bd2ad31194e1f99d84eec6",
  "image.name": "ghcr.io/graphql-hive/policy:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/policy:feat_cli_fields_selector-amd64"
},
"rate-limit": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The rate limit service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/rate-limit",
          "build-arg:PORT": "3009",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/rate-limit",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/kran6xz7jwsoh15kfzqpp7sa4",
  "containerimage.config.digest": "sha256:105ec403b76c68f44ddcd13731e607eaf0dee09b3ea4665001adc352c6d61b05",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:d1d8d6ff30cb68867d2be5f13f0f1bc9a3fe1fbe58c9d872797db834124231b7",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:d1d8d6ff30cb68867d2be5f13f0f1bc9a3fe1fbe58c9d872797db834124231b7",
  "image.name": "ghcr.io/graphql-hive/rate-limit:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/rate-limit:feat_cli_fields_selector-amd64"
},
"schema": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The schema service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/schema",
          "build-arg:PORT": "3002",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/schema",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/n6t8vbina05gulnntx7odkmv1",
  "containerimage.config.digest": "sha256:86f27e4f8d6c68be8af1dcdb8b516e47eda979e6d8b7043c20cc6d287572412b",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:40f8a159d4e01908da8e9cb5bb292521a4d6f434cefde9b33d383781ce5e36f2",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:40f8a159d4e01908da8e9cb5bb292521a4d6f434cefde9b33d383781ce5e36f2",
  "image.name": "ghcr.io/graphql-hive/schema:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/schema:feat_cli_fields_selector-amd64"
},
"server": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The server service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/server",
          "build-arg:PORT": "3001",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/server",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/5ao08if9n1yicwg8r0av2xmfd",
  "containerimage.config.digest": "sha256:8d36a0970712759c65d8bdf76092d1e77b74c6d1406ef9077dab87162e9d3e15",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:af7cb5c4dcf653da659437e726c167bc53f78d0c3bddc40c02a06fc96a92f7da",
    "size": 2076,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:af7cb5c4dcf653da659437e726c167bc53f78d0c3bddc40c02a06fc96a92f7da",
  "image.name": "ghcr.io/graphql-hive/server:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/server:feat_cli_fields_selector-amd64"
},
"storage": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "migrations.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:IMAGE_DESCRIPTION": "The migrations service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/storage",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/i6yns2aarbj5lz3racciymvou",
  "containerimage.config.digest": "sha256:fc1ce3b4df2a10cf6aa2d11c84e4340ba389c2874accbc7939463e4f5b7e125a",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:cd6c9553f127ae45471eb745ab2a9a871948156f566ba1b003a79c1b2c8347e0",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:cd6c9553f127ae45471eb745ab2a9a871948156f566ba1b003a79c1b2c8347e0",
  "image.name": "ghcr.io/graphql-hive/storage:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/storage:feat_cli_fields_selector-amd64"
},
"stripe-billing": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The stripe billing service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/stripe-billing",
          "build-arg:PORT": "3010",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/stripe-billing",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/li1dcqi29ood6ty3nf2ococya",
  "containerimage.config.digest": "sha256:5c190eb47c3c99040eb292bfda71b669fe5fed88836c7f92964c0cb93f6e6f2d",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:8b8e5db277859526b4a73934beb21eee8793a1e5fe187859280a1889818f051a",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:8b8e5db277859526b4a73934beb21eee8793a1e5fe187859280a1889818f051a",
  "image.name": "ghcr.io/graphql-hive/stripe-billing:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/stripe-billing:feat_cli_fields_selector-amd64"
},
"tokens": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The tokens service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/tokens",
          "build-arg:PORT": "3003",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/tokens",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/avptp062rbroi7fgy7mgrxv5h",
  "containerimage.config.digest": "sha256:c0b41eddae3ec3c22ec1a0c5e7b3aec4c6f0b1380f2bcc2df79e9baa24832683",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:3e5bf2ecfd7e909355094db867acbd647fc73e77412d48eaae337be7da85285d",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:3e5bf2ecfd7e909355094db867acbd647fc73e77412d48eaae337be7da85285d",
  "image.name": "ghcr.io/graphql-hive/tokens:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/tokens:feat_cli_fields_selector-amd64"
},
"usage": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The usage ingestor service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/usage",
          "build-arg:PORT": "3006",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/usage",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/ld6ti8sabjvkmuyeiwakz2tri",
  "containerimage.config.digest": "sha256:ae3767b0acfbd84fa990540a39781cb9323a3e7db1ae506691fcb6bfc8fefd56",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:5ef0798c63c65d88bce3dc941156e306bb27749cec5746b0a49778e34a1916c9",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:5ef0798c63c65d88bce3dc941156e306bb27749cec5746b0a49778e34a1916c9",
  "image.name": "ghcr.io/graphql-hive/usage:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/usage:feat_cli_fields_selector-amd64"
},
"usage-estimator": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The usage estimator service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/usage-estimator",
          "build-arg:PORT": "3008",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/usage-estimator",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/zz0n0zek223ig6vcdktfkmt4i",
  "containerimage.config.digest": "sha256:7e21fc303782f0ce1b02bd731228224340623e2c269d864254a113c1b29571ed",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:e750b78944f1a57b916e66f2ee374f4f4a981ab26c651ebd938a1d61c593c12b",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:e750b78944f1a57b916e66f2ee374f4f4a981ab26c651ebd938a1d61c593c12b",
  "image.name": "ghcr.io/graphql-hive/usage-estimator:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/usage-estimator:feat_cli_fields_selector-amd64"
},
"usage-ingestor": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The usage ingestor service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/usage-ingestor",
          "build-arg:PORT": "3007",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/usage-ingestor",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/vp7r8ta05vw81bxz3c7w0bxg6",
  "containerimage.config.digest": "sha256:32b829f2bca1ccbf6485e9b63a5997a90e6ac68a8666f676d65d3f74c158a601",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:b933ce9107c9ff7259684a7ad89c33676258b8621299b7921e3423ca15242fce",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:b933ce9107c9ff7259684a7ad89c33676258b8621299b7921e3423ca15242fce",
  "image.name": "ghcr.io/graphql-hive/usage-ingestor:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/usage-ingestor:feat_cli_fields_selector-amd64"
},
"webhooks": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Famd64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The webhooks ingestor service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/webhooks",
          "build-arg:PORT": "3005",
          "build-arg:RELEASE": "58e59db9d0c22995111323e922c592fea7a42c63",
          "build-arg:SERVICE_DIR_NAME": "@hive/webhooks",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:dockerfile": "sn2lymtv06vtmdammii44nj3u",
          "local-sessionid:shared": "sn2lymtv06vtmdammii44nj3u"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/amd64"
      }
    }
  },
  "buildx.build.ref": "builder-27448a90-1100-4832-a6a2-8e97f755f0d7/builder-27448a90-1100-4832-a6a2-8e97f755f0d70/52eedhx0lbsmtd0qs5go815t9",
  "containerimage.config.digest": "sha256:b6525202a837301c252bd1c90ab7445b69f3ad7d6132c61995f545fad63c315c",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:87a4cfdc1402f6315f68e2ec6382e802b7e83193a359efe80516516ba548eaed",
    "size": 2075,
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:87a4cfdc1402f6315f68e2ec6382e802b7e83193a359efe80516516ba548eaed",
  "image.name": "ghcr.io/graphql-hive/webhooks:58e59db9d0c22995111323e922c592fea7a42c63-amd64,ghcr.io/graphql-hive/webhooks:feat_cli_fields_selector-amd64"
}
}

@n1ru4l
Copy link
Contributor Author

n1ru4l commented Jan 31, 2025

@coderabbitai review

Copy link

coderabbitai bot commented Jan 31, 2025

📝 Walkthrough

Summary by CodeRabbit

Based on the comprehensive summary, here are the release notes:

Release Notes

  • New Features

    • Added support for specifying targets across various CLI commands
    • Enhanced schema management with more granular target control
  • Improvements

    • Improved error handling for invalid target specifications
    • Streamlined target resolution across schema-related operations
    • Enhanced tracing and logging for schema management
  • Bug Fixes

    • Resolved inconsistencies in target-based authentication and authorization
  • Breaking Changes

    • Removed legacy token-based ID retrieval methods
    • Modified GraphQL schema to include target parameters

These changes introduce more flexible and precise target management for schema operations, with improved error handling and logging capabilities.

Walkthrough

This pull request introduces a comprehensive enhancement to the CLI and API modules, focusing on target-based operations for schema management. The changes primarily revolve around adding a new target parameter across various commands and resolvers, implementing robust target slug parsing, and improving error handling for target-related operations. The modifications span multiple files in the CLI and API services, introducing more granular control and validation for schema-related actions like publishing, checking, fetching, and deleting schemas.

Changes

File Change Summary
integration-tests/testkit/cli-snapshot-serializer.ts Added new variable replacement pattern for masking request IDs
integration-tests/tests/cli/schema.spec.ts Added test cases for schema:publish with target parameter validation
packages/libraries/cli/src/commands/schema/* Added target flag to schema-related commands with validation and error handling
packages/services/api/src/modules/schema/* Updated GraphQL schema, resolvers, and providers to support target-based operations
packages/services/api/src/helpers/target-slug.ts Introduced new parsing mechanism for target slugs
packages/services/api/src/helpers/errors.ts Added InvalidTargetError for target-related error handling

Possibly related PRs

  • fix: check uuid #6446: Changes to findSchemaCheckForTarget method in schema-manager, which might be tangentially related to target handling improvements

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
packages/libraries/cli/src/helpers/target-slug.ts (1)

20-22: Consider Node.js version compatibility.

The array.at() method was introduced in Node.js 16.6.0. Consider using array indexing for better compatibility with older Node.js versions.

-  const organizationSlug = parts.at(0);
-  const projectSlug = parts.at(1);
-  const targetSlug = parts.at(2);
+  const organizationSlug = parts[0];
+  const projectSlug = parts[1];
+  const targetSlug = parts[2];
packages/libraries/cli/src/commands/schema/delete.ts (1)

146-154: Consider adding target validation in dry run mode.

While the implementation is correct, consider adding a note in the output when using --dryRun to indicate which target would be affected.

 const result = await this.registryApi(endpoint, accessToken).request({
   operation: schemaDeleteMutation,
   variables: {
     input: {
       serviceName: service,
       dryRun: flags.dryRun,
       target,
     },
   },
 });
+if (flags.dryRun && target) {
+  this.logInfo(`Target: ${flags.target}`);
+}
packages/services/api/src/modules/schema/module.graphql.ts (1)

269-269: LGTM! Consider adding field descriptions.

The addition of the target field to input types is consistent and well-structured. However, consider adding descriptions to the target fields to improve schema documentation.

Add descriptions to the target fields:

 input SchemaPublishInput {
+  """
+  Target selector for the schema operation.
+  """
   target: TargetSelectorInput
   service: ID
   # ... rest of the fields
 }

 input SchemaComposeInput {
+  """
+  Target selector for the schema operation.
+  """
   target: TargetSelectorInput
   services: [SchemaComposeServiceInput!]!
   # ... rest of the fields
 }

 input SchemaCheckInput {
+  """
+  Target selector for the schema operation.
+  """
   target: TargetSelectorInput
   service: ID
   # ... rest of the fields
 }

 input SchemaDeleteInput {
+  """
+  Target selector for the schema operation.
+  """
   target: TargetSelectorInput
   serviceName: ID!
   # ... rest of the fields
 }

Also applies to: 297-297, 581-581, 594-594

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e17e06f and 3649188.

📒 Files selected for processing (23)
  • integration-tests/testkit/cli-snapshot-serializer.ts (1 hunks)
  • integration-tests/tests/cli/schema.spec.ts (2 hunks)
  • packages/libraries/cli/src/commands/schema/check.ts (5 hunks)
  • packages/libraries/cli/src/commands/schema/delete.ts (3 hunks)
  • packages/libraries/cli/src/commands/schema/fetch.ts (7 hunks)
  • packages/libraries/cli/src/commands/schema/publish.ts (5 hunks)
  • packages/libraries/cli/src/helpers/errors.ts (1 hunks)
  • packages/libraries/cli/src/helpers/target-slug.ts (1 hunks)
  • packages/services/api/src/modules/auth/lib/authz.ts (3 hunks)
  • packages/services/api/src/modules/organization/providers/organization-manager.ts (1 hunks)
  • packages/services/api/src/modules/organization/providers/organization-members.ts (1 hunks)
  • packages/services/api/src/modules/project/providers/project-manager.ts (0 hunks)
  • packages/services/api/src/modules/schema/module.graphql.ts (5 hunks)
  • packages/services/api/src/modules/schema/providers/schema-manager.ts (7 hunks)
  • packages/services/api/src/modules/schema/providers/schema-publisher.ts (19 hunks)
  • packages/services/api/src/modules/schema/resolvers/Mutation/schemaCheck.ts (1 hunks)
  • packages/services/api/src/modules/schema/resolvers/Mutation/schemaCompose.ts (1 hunks)
  • packages/services/api/src/modules/schema/resolvers/Mutation/schemaDelete.ts (1 hunks)
  • packages/services/api/src/modules/schema/resolvers/Mutation/schemaPublish.ts (0 hunks)
  • packages/services/api/src/modules/schema/resolvers/Query/latestValidVersion.ts (1 hunks)
  • packages/services/api/src/modules/schema/resolvers/Query/schemaVersionForActionId.ts (1 hunks)
  • packages/services/api/src/modules/shared/providers/id-translator.ts (4 hunks)
  • packages/services/api/src/modules/target/providers/target-manager.ts (0 hunks)
💤 Files with no reviewable changes (3)
  • packages/services/api/src/modules/project/providers/project-manager.ts
  • packages/services/api/src/modules/schema/resolvers/Mutation/schemaPublish.ts
  • packages/services/api/src/modules/target/providers/target-manager.ts
🧰 Additional context used
📓 Path-based instructions (20)
integration-tests/testkit/cli-snapshot-serializer.ts (1)

Pattern integration-tests/**: integration tests for ensuring features and important flows are running. Usually, changes to the packages/ directory will affect this. In ideal flow, each PR should include integration tests.

packages/libraries/cli/src/helpers/errors.ts (2)

Pattern packages/libraries/cli/**: The CLI to interact with Hive Console APIs.


Pattern packages/libraries/**: Most of the dirs here are NPM packages that provides our customers an integration library, in order to get/fetch data from Hive Console API or Hive CDN.

packages/services/api/src/modules/auth/lib/authz.ts (1)

Pattern packages/services/**: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with -worker are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
The cdn-worker is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).

integration-tests/tests/cli/schema.spec.ts (1)

Pattern integration-tests/**: integration tests for ensuring features and important flows are running. Usually, changes to the packages/ directory will affect this. In ideal flow, each PR should include integration tests.

packages/libraries/cli/src/commands/schema/delete.ts (2)

Pattern packages/libraries/cli/**: The CLI to interact with Hive Console APIs.


Pattern packages/libraries/**: Most of the dirs here are NPM packages that provides our customers an integration library, in order to get/fetch data from Hive Console API or Hive CDN.

packages/services/api/src/modules/organization/providers/organization-manager.ts (1)

Pattern packages/services/**: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with -worker are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
The cdn-worker is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).

packages/services/api/src/modules/organization/providers/organization-members.ts (1)

Pattern packages/services/**: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with -worker are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
The cdn-worker is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).

packages/services/api/src/modules/schema/resolvers/Mutation/schemaDelete.ts (1)

Pattern packages/services/**: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with -worker are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
The cdn-worker is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).

packages/services/api/src/modules/shared/providers/id-translator.ts (1)

Pattern packages/services/**: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with -worker are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
The cdn-worker is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).

packages/services/api/src/modules/schema/resolvers/Mutation/schemaCheck.ts (1)

Pattern packages/services/**: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with -worker are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
The cdn-worker is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).

packages/libraries/cli/src/commands/schema/publish.ts (2)

Pattern packages/libraries/cli/**: The CLI to interact with Hive Console APIs.


Pattern packages/libraries/**: Most of the dirs here are NPM packages that provides our customers an integration library, in order to get/fetch data from Hive Console API or Hive CDN.

packages/services/api/src/modules/schema/resolvers/Mutation/schemaCompose.ts (1)

Pattern packages/services/**: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with -worker are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
The cdn-worker is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).

packages/libraries/cli/src/helpers/target-slug.ts (2)

Pattern packages/libraries/cli/**: The CLI to interact with Hive Console APIs.


Pattern packages/libraries/**: Most of the dirs here are NPM packages that provides our customers an integration library, in order to get/fetch data from Hive Console API or Hive CDN.

packages/services/api/src/modules/schema/resolvers/Query/latestValidVersion.ts (1)

Pattern packages/services/**: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with -worker are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
The cdn-worker is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).

packages/libraries/cli/src/commands/schema/check.ts (2)

Pattern packages/libraries/cli/**: The CLI to interact with Hive Console APIs.


Pattern packages/libraries/**: Most of the dirs here are NPM packages that provides our customers an integration library, in order to get/fetch data from Hive Console API or Hive CDN.

packages/libraries/cli/src/commands/schema/fetch.ts (2)

Pattern packages/libraries/cli/**: The CLI to interact with Hive Console APIs.


Pattern packages/libraries/**: Most of the dirs here are NPM packages that provides our customers an integration library, in order to get/fetch data from Hive Console API or Hive CDN.

packages/services/api/src/modules/schema/resolvers/Query/schemaVersionForActionId.ts (1)

Pattern packages/services/**: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with -worker are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
The cdn-worker is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).

packages/services/api/src/modules/schema/providers/schema-publisher.ts (1)

Pattern packages/services/**: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with -worker are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
The cdn-worker is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).

packages/services/api/src/modules/schema/providers/schema-manager.ts (1)

Pattern packages/services/**: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with -worker are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
The cdn-worker is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).

packages/services/api/src/modules/schema/module.graphql.ts (1)

Pattern packages/services/**: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with -worker are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
The cdn-worker is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).

🔇 Additional comments (94)
packages/services/api/src/modules/shared/providers/id-translator.ts (4)

3-3: Import statement looks good.


15-15: Exporting TargetSelectorInput interface is appropriate.


26-26: Constructor parameter addition approved.


89-140: Consider verifying the legacy selector fallback.

If this.session.getLegacySelector() returns a null or incomplete selector, the code proceeds without error handling. Ensuring validity might prevent unexpected null references downstream.

packages/services/api/src/modules/schema/providers/schema-manager.ts (17)

6-6: Import statement is fine.


28-28: Importing Session and InsufficientPermissionError is good for explicit error handling.


32-32: Importing IdTranslator and TargetSelectorInput is consistent with the new approach.


87-87: New constructor parameter for IdTranslator is fine.


104-106: Tracing attributes added for slug usage.


111-119: Method signature change to accept target parameter is consistent with new logic.


122-127: Use of resolveTargetSlugSelector for target resolution is clear and robust.


128-132: Tracing settings with resolved IDs is appropriate.


137-137: Checked permission with updated organization ID reference.


139-140: Consistent usage of resolved IDs in the canPerformAction call.


194-194: Passing the targetId from resolved selector looks correct.


990-999: New method getSchemaVersionByActionId references IdTranslator for target resolution.


1002-1003: Log attributes referencing the newly resolved projectId & targetId.


1009-1009: Ensuring the session checks organization scope via resolved ID.


1011-1013: Refined permission parameters match the resolved IDs.


1018-1019: Storage call referencing resolved project/target IDs is inline with the consistent approach.


1029-1031: Including the organizationId in the return object is correct.

packages/services/api/src/modules/schema/providers/schema-publisher.ts (49)

9-9: Trace imports are fine.


23-23: Explicit import of Session and InsufficientPermissionError is appropriate.


31-31: Dependency on IdTranslator is noted.


78-78: New CheckInput type reference is well-defined.


80-80: DeleteInput type reference is straightforward.


82-84: Extended PublishInput with isSchemaPublishMissingUrlErrorSelected flag is acceptable.


141-141: Including private idTranslator: IdTranslator in constructor is aligned with the new approach.


255-257: Controlled tracing of slugs for the schema check is consistent with the introduced pattern.


266-271: resolveTargetSlugSelector usage is clear and ensures permission error on failure.


278-278: Additional trace attributes with resolved IDs are beneficial for debugging.


281-281: Organization ID utilized for session permission checks.


293-295: Refined IDs from the resolved selector for storage usage.


298-299: Consistent usage of resolved organizationId and projectId.


302-302: Sharing the previously resolved organizationId.


305-307: Further references to organization, project, and target ID for storage queries.


310-312: Ensuring only composable schemas are retrieved with the resolved IDs.


963-965: Slug-based tracing for schema publisher input is consistent.


974-979: Leveraging resolveTargetSlugSelector in publish method with custom onError.


981-986: Adding trace attributes for resolved IDs is appropriate.


987-996: Permission check transitions to use the resolved selector fields.


1000-1002: Additional trace usage for slug-based data in the publish method.


1012-1012: Active contract retrieval referencing selector.targetId.


1016-1017: Fallback reference to legacySelector for hashing.


1022-1024: Including resolved IDs in the hash computation payload.


1036-1036: Verify handling of sensitive data.

You're hashing legacySelector.token here. Ensure that this token string isn't inadvertently exposed in logs. Confirm that it’s never directly logged, as even hashed data can sometimes reveal patterns in usage.


1041-1043: Usage of resolved IDs in logging is correct.


1048-1048: Using a lock ID keyed by the resolved target ID is consistent.


1070-1070: Passing selector through to internalPublish ensures consistent referencing.


1089-1091: Tracing slug attributes for the deletion action.


1100-1105: Target resolution for the delete method is consistent with the new approach.


1107-1112: Attaching ID-based trace attributes for the target to be deleted.


1113-1122: Session permission check with resolved IDs for schemaVersion:deleteService.


1124-1135: Checksum computation includes legacySelector.token.


1137-1137: Lock ID derived from the resolved target ID for the deletion mutex.


1145-1145: Ensuring organizationId is included for the next steps.


1148-1149: Consistent usage of resolved IDs.


1152-1154: Ensuring the correct target is retrieved via resolved IDs.


1157-1159: Fetching latest schemas for the newly resolved target.


1162-1164: Including onlyComposable param with the same resolved IDs.


1168-1170: Retrieving base schema for the resolved target.


1180-1180: Inline reference to selector.targetId for comparing composition versions.


1220-1222: Passing the resolved target, project, and organization IDs into the new method.


1229-1229: Target ID used for active contract lookup.


1253-1255: Ensuring the final delete operation references the correct IDs.


1319-1319: Accurately passing target to the CDNs for updates.


1331-1333: Including resolved IDs for conditional breaking change metadata.


1352-1352: Passing the resolved target to notification triggers.


1411-1411: TargetSelector included as a parameter in internalPublish ensures consistent ID usage throughout.


1415-1417: Logging and referencing the newly resolved organization, project, and target IDs is correct.

packages/services/api/src/modules/schema/resolvers/Query/schemaVersionForActionId.ts (1)

6-10: LGTM! Clean implementation of the target parameter.

The changes properly handle the optional target parameter with a null default value.

packages/services/api/src/modules/schema/resolvers/Mutation/schemaDelete.ts (1)

13-13: LGTM! Clean implementation of the target parameter.

The changes properly pass the target parameter to the SchemaPublisher.

packages/services/api/src/modules/schema/resolvers/Mutation/schemaCheck.ts (1)

12-12: LGTM! Clean implementation of the target parameter.

The changes properly handle the optional target parameter with a null default value.

packages/services/api/src/modules/schema/resolvers/Mutation/schemaCompose.ts (1)

12-12: LGTM! Clean and backward-compatible target handling.

The addition of optional target support using nullish coalescing maintains backward compatibility while enabling target-specific schema composition.

packages/services/api/src/modules/schema/resolvers/Query/latestValidVersion.ts (2)

11-18: LGTM! Robust target ID resolution with fallback.

The implementation correctly handles both new target-based access and legacy selector-based access, ensuring backward compatibility.


20-21: Verify target existence before usage.

Consider adding error handling for cases where the target doesn't exist.

integration-tests/testkit/cli-snapshot-serializer.ts (1)

48-51: LGTM! Consistent masking pattern for request IDs.

The new pattern follows the established masking convention and correctly handles request ID values in test output.

packages/libraries/cli/src/commands/schema/delete.ts (2)

82-84: LGTM! Clear and well-documented target flag.

The flag definition follows CLI conventions and includes a clear description.


138-145: LGTM! Robust target validation.

The implementation properly validates the target slug and handles errors appropriately.

packages/libraries/cli/src/commands/schema/fetch.ts (3)

6-6: LGTM!

The imports are correctly added and are necessary for the new target functionality.

Also applies to: 10-10, 16-16


25-27: LGTM!

The GraphQL queries are correctly updated to include the target parameter with proper typing.

Also applies to: 57-59


173-180: LGTM!

The target handling logic is correctly implemented with proper error handling and the target is correctly passed to the GraphQL queries.

Also applies to: 191-191, 202-202

packages/libraries/cli/src/commands/schema/check.ts (2)

5-6: LGTM!

The imports are correctly added and are necessary for the new target functionality.

Also applies to: 11-11, 26-26


178-185: LGTM!

The target handling logic is correctly implemented with proper error handling and the target is correctly passed to the GraphQL mutation.

Also applies to: 272-272

packages/libraries/cli/src/commands/schema/publish.ts (3)

6-6: LGTM!

The imports are correctly added and are necessary for the new target functionality.

Also applies to: 13-13, 24-24


149-151: LGTM!

The target flag is correctly added with an appropriate description for the publish command.


270-277: LGTM!

The target handling logic is correctly implemented with proper error handling and the target is correctly passed to the GraphQL mutation.

Also applies to: 309-309

integration-tests/tests/cli/schema.spec.ts (2)

359-388: LGTM! Well-structured test for successful target parameter usage.

The test case thoroughly verifies that schema publishing succeeds when the target parameter matches the access token. Good use of inline snapshots for validation.


390-426: LGTM! Comprehensive test for invalid target parameter handling.

The test case properly verifies that schema publishing fails with an appropriate error message when the target parameter doesn't match the access token. The error message and exit code assertions are clear and accurate.

packages/services/api/src/modules/auth/lib/authz.ts (2)

188-188: LGTM! Improved error handling specificity.

The replacement of AccessError with InsufficientPermissionError provides more precise error reporting for permission-related issues.

Also applies to: 204-204


235-239: LGTM! Well-structured error class.

The InsufficientPermissionError class is well-designed:

  • Extends the base AccessError class
  • Provides clear, action-specific error messages
  • Takes advantage of TypeScript's type system with the actionDefinitions key
packages/services/api/src/modules/organization/providers/organization-members.ts (1)

Line range hint 228-238: LGTM! Well-implemented organization members retrieval.

The new method efficiently:

  • Logs debug information
  • Retrieves organization members
  • Resolves memberships with proper error handling
packages/services/api/src/modules/organization/providers/organization-manager.ts (1)

6-6: LGTM! Simplified organization access pattern.

The removal of token-based organization lookup methods aligns with the move towards more explicit permission checks and improved schema management access control.

packages/services/api/src/modules/schema/module.graphql.ts (1)

33-34: LGTM! Query changes look good.

The addition of the target parameter to schemaVersionForActionId and the new latestValidVersion query are well-structured and consistent with the schema's design.

Comment on lines 17 to 38
export function parse(str: string): ParseError | ParseOk {
const parts = str.split('/');

const organizationSlug = parts.at(0);
const projectSlug = parts.at(1);
const targetSlug = parts.at(2);

if (!organizationSlug || !projectSlug || !targetSlug) {
return {
type: 'error',
};
}

return {
type: 'ok',
data: {
organizationSlug,
projectSlug,
targetSlug,
},
};
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add input validation and error handling.

The parse function could be more robust with additional validations:

  1. Input validation for empty string or non-string input
  2. Trimming of whitespace
  3. Validation of slug format (e.g., allowed characters)

Here's a suggested implementation:

 export function parse(str: string): ParseError | ParseOk {
+  if (!str || typeof str !== 'string') {
+    return { type: 'error' };
+  }
+
+  const trimmed = str.trim();
+  if (!trimmed) {
+    return { type: 'error' };
+  }
+
   const parts = str.split('/');
 
   const organizationSlug = parts.at(0);
   const projectSlug = parts.at(1);
   const targetSlug = parts.at(2);
 
-  if (!organizationSlug || !projectSlug || !targetSlug) {
+  if (!organizationSlug?.trim() || !projectSlug?.trim() || !targetSlug?.trim()) {
     return {
       type: 'error',
     };
   }
 
+  // Validate slug format (alphanumeric, hyphens, and underscores only)
+  const slugRegex = /^[a-zA-Z0-9-_]+$/;
+  if (
+    !slugRegex.test(organizationSlug) ||
+    !slugRegex.test(projectSlug) ||
+    !slugRegex.test(targetSlug)
+  ) {
+    return { type: 'error' };
+  }
+
   return {
     type: 'ok',
     data: {
-      organizationSlug,
-      projectSlug,
-      targetSlug,
+      organizationSlug: organizationSlug.trim(),
+      projectSlug: projectSlug.trim(),
+      targetSlug: targetSlug.trim(),
     },
   };
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function parse(str: string): ParseError | ParseOk {
const parts = str.split('/');
const organizationSlug = parts.at(0);
const projectSlug = parts.at(1);
const targetSlug = parts.at(2);
if (!organizationSlug || !projectSlug || !targetSlug) {
return {
type: 'error',
};
}
return {
type: 'ok',
data: {
organizationSlug,
projectSlug,
targetSlug,
},
};
}
export function parse(str: string): ParseError | ParseOk {
if (!str || typeof str !== 'string') {
return { type: 'error' };
}
const trimmed = str.trim();
if (!trimmed) {
return { type: 'error' };
}
const parts = str.split('/');
const organizationSlug = parts.at(0);
const projectSlug = parts.at(1);
const targetSlug = parts.at(2);
if (!organizationSlug?.trim() || !projectSlug?.trim() || !targetSlug?.trim()) {
return {
type: 'error',
};
}
// Validate slug format (alphanumeric, hyphens, and underscores only)
const slugRegex = /^[a-zA-Z0-9-_]+$/;
if (
!slugRegex.test(organizationSlug) ||
!slugRegex.test(projectSlug) ||
!slugRegex.test(targetSlug)
) {
return { type: 'error' };
}
return {
type: 'ok',
data: {
organizationSlug: organizationSlug.trim(),
projectSlug: projectSlug.trim(),
targetSlug: targetSlug.trim(),
},
};
}

packages/libraries/cli/src/commands/schema/fetch.ts Outdated Show resolved Hide resolved
packages/libraries/cli/src/commands/schema/check.ts Outdated Show resolved Hide resolved
packages/libraries/cli/src/helpers/errors.ts Outdated Show resolved Hide resolved
n1ru4l and others added 3 commits January 31, 2025 12:29
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@n1ru4l n1ru4l force-pushed the feat-cli-fields-selector branch from dc38827 to b6968db Compare January 31, 2025 13:23
Comment on lines 75 to 82
let target: GraphQLSchema.TargetSelectorInput | null = null;
if (flags.target) {
const result = TargetSlug.parse(flags.target);
if (result.type === 'error') {
throw new InvalidTargetError();
}
target = result.data;
}
Copy link
Contributor Author

@n1ru4l n1ru4l Jan 31, 2025

Choose a reason for hiding this comment

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

Not sure if already too aggressive: We could start logging a warning here if --target is not provided.

Copy link
Contributor

Choose a reason for hiding this comment

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

process.exit(1) to make sure people see it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants