-
Notifications
You must be signed in to change notification settings - Fork 107
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
feat: organization access tokens #6493
base: main
Are you sure you want to change the base?
Conversation
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the 📝 WalkthroughSummary by CodeRabbit
WalkthroughThis pull request introduces integration tests and GraphQL API enhancements for managing organization access tokens. It adds new mutations for creating and deleting tokens along with corresponding resolvers and provider classes. A new migration creates the necessary database table, and related package configuration updates, dependency patches, and export mappings are implemented. The authentication and authorization modules are refactored to support token-based access while reorganizing permission definitions and resource assignment logic throughout the organization module. Additionally, changes in shared utilities and server configuration update the access token strategy and error handling. Changes
Sequence Diagram(s)sequenceDiagram
participant C as Client
participant GS as GraphQL Server
participant R as Resolver (createOrganizationAccessToken)
participant P as OrganizationAccessTokens Provider
participant DB as Database
participant Cache as OrganizationAccessTokensCache
C->>GS: Send createOrganizationAccessToken mutation (input)
GS->>R: Forward mutation input
R->>P: Call create() with input data
P->>DB: Insert new token record
DB-->>P: Return created token data
P->>Cache: Add token to cache
P-->>R: Return token details and private access key
R-->>GS: Respond with success object
GS-->>C: Return token data and access key
sequenceDiagram
participant C as Client
participant GS as GraphQL Server
participant DR as Resolver (deleteOrganizationAccessToken)
participant P as OrganizationAccessTokens Provider
participant DB as Database
participant Cache as OrganizationAccessTokensCache
C->>GS: Send deleteOrganizationAccessToken mutation (token ID)
GS->>DR: Forward mutation input
DR->>P: Call delete() with token ID
P->>DB: Delete token record
DB-->>P: Confirm deletion
P->>Cache: Purge token from cache
P-->>DR: Return deletion confirmation
DR-->>GS: Respond with deletion success
GS-->>C: Return deletion result
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
🚀 Snapshot Release (
|
Package | Version | Info |
---|---|---|
@graphql-hive/cli |
0.48.2-alpha-20250212122623-1ff10816d44ee474c802b10c555435fe75f98016 |
npm ↗︎ unpkg ↗︎ |
hive |
5.1.1-alpha-20250212122623-1ff10816d44ee474c802b10c555435fe75f98016 |
npm ↗︎ unpkg ↗︎ |
🐋 This PR was built and pushed to the following Docker images: Targets: Platforms: Image Tag: Docker Bake metadata{
"app": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/qda2iooldodnyz3jcc2v3xh2j",
"containerimage.config.digest": "sha256:0ac3d33fd5d89d55c60f22ee7447c334b63a67a20de7a803c8ae56aab506daa3",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:0be1befbe32da4365af6a3e7c86d1a5ac0f70b2b014b70c501fb32a9619cb36b",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:0be1befbe32da4365af6a3e7c86d1a5ac0f70b2b014b70c501fb32a9619cb36b",
"image.name": "ghcr.io/graphql-hive/app:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/app:wip_organization_access_tokens-arm64"
},
"buildx.build.warnings": [
{
"vertex": "sha256:9990a4502c9b1bfe3e00af65bdf72c5fcec88aa282e2090ec57b0214cafdc537",
"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:368c92bff6a328559d46cc19c7a755dc09d6f30ba6d05c91bd66a042bef4f11f",
"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
}
}
]
},
{
"vertex": "sha256:368c92bff6a328559d46cc19c7a755dc09d6f30ba6d05c91bd66a042bef4f11f",
"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:9990a4502c9b1bfe3e00af65bdf72c5fcec88aa282e2090ec57b0214cafdc537",
"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:9990a4502c9b1bfe3e00af65bdf72c5fcec88aa282e2090ec57b0214cafdc537",
"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:9990a4502c9b1bfe3e00af65bdf72c5fcec88aa282e2090ec57b0214cafdc537",
"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:368c92bff6a328559d46cc19c7a755dc09d6f30ba6d05c91bd66a042bef4f11f",
"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:368c92bff6a328559d46cc19c7a755dc09d6f30ba6d05c91bd66a042bef4f11f",
"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:9990a4502c9b1bfe3e00af65bdf72c5fcec88aa282e2090ec57b0214cafdc537",
"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:9990a4502c9b1bfe3e00af65bdf72c5fcec88aa282e2090ec57b0214cafdc537",
"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:9990a4502c9b1bfe3e00af65bdf72c5fcec88aa282e2090ec57b0214cafdc537",
"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:9990a4502c9b1bfe3e00af65bdf72c5fcec88aa282e2090ec57b0214cafdc537",
"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:368c92bff6a328559d46cc19c7a755dc09d6f30ba6d05c91bd66a042bef4f11f",
"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:368c92bff6a328559d46cc19c7a755dc09d6f30ba6d05c91bd66a042bef4f11f",
"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
}
}
]
}
],
"composition-federation-2": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/nse9b0zjyxns8m0uto55aq19j",
"containerimage.config.digest": "sha256:f13271a41b202397991532303193bd11c111d121ffb5cae3c0c132fca042500e",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:e94e243a68c9f5b8cf12c68108a5e3ac0e6c053dc95e957fc6bbd687b90d87ac",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:e94e243a68c9f5b8cf12c68108a5e3ac0e6c053dc95e957fc6bbd687b90d87ac",
"image.name": "ghcr.io/graphql-hive/composition-federation-2:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/composition-federation-2:wip_organization_access_tokens-arm64"
},
"emails": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/fwizv6kd52v339ky1gamouhi0",
"containerimage.config.digest": "sha256:ceee69fb8bbcae5448f14f2381d5a4df407f21da281395827b427fcc952c5ff4",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:10838c270a1377b508caf48b2f6dc58b989ce544b9477536169733a6742f68af",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:10838c270a1377b508caf48b2f6dc58b989ce544b9477536169733a6742f68af",
"image.name": "ghcr.io/graphql-hive/emails:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/emails:wip_organization_access_tokens-arm64"
},
"policy": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/1bdir9ze87v4n8u48ii2bqru1",
"containerimage.config.digest": "sha256:6df31dea03da4ea077143ba662185e8598160c26c599d86ebf0a3a22543a4067",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:c88431804706ddb7fa556acad8acfa3854f2e65d39c932727e5dad08da7838a4",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:c88431804706ddb7fa556acad8acfa3854f2e65d39c932727e5dad08da7838a4",
"image.name": "ghcr.io/graphql-hive/policy:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/policy:wip_organization_access_tokens-arm64"
},
"rate-limit": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/cwxd729jwdmtlngklh0wg5w1c",
"containerimage.config.digest": "sha256:4a8090bc9123871894698f9b586eb062945ab4c4ffc4ebc0d92af02471b50dfc",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:a11778b0c332aaadd8713a46c6b7f6a3dffe6ea14252a329f1baa176b4a57c11",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:a11778b0c332aaadd8713a46c6b7f6a3dffe6ea14252a329f1baa176b4a57c11",
"image.name": "ghcr.io/graphql-hive/rate-limit:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/rate-limit:wip_organization_access_tokens-arm64"
},
"schema": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/tw7zc2px7cnpcc6ll2qe2fsf4",
"containerimage.config.digest": "sha256:1bec9e23909b031bbcc211b2b86648a745568cf6356eb6ab70fdd9cd4d557bfb",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:4416fc7fd637fbf2dc1a8565b2e9097b386332d351ab3899c1e31c4994a2a02a",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:4416fc7fd637fbf2dc1a8565b2e9097b386332d351ab3899c1e31c4994a2a02a",
"image.name": "ghcr.io/graphql-hive/schema:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/schema:wip_organization_access_tokens-arm64"
},
"server": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/iqd24h6hy3c0t38mi0v6463c3",
"containerimage.config.digest": "sha256:021a78c037eebd561e64e3baabfc19977514d61441efcc09747feeff1cf892d9",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:b2f40d5b823d195bc6ed69727d900626dc81053f755f3b6c628c98dc1840ee47",
"size": 2076,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:b2f40d5b823d195bc6ed69727d900626dc81053f755f3b6c628c98dc1840ee47",
"image.name": "ghcr.io/graphql-hive/server:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/server:wip_organization_access_tokens-arm64"
},
"storage": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/l27p2lwee3375srjx0f0vya4q",
"containerimage.config.digest": "sha256:bc552f0a77cbfc3cb4030245f01d8c8acbc2bb623d3af7be270c758dc6a0338f",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:37ea3f38daf1226eef8b38e16c04be4b47f7d7c0e6b39afd728e4f1e6e2fffcc",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:37ea3f38daf1226eef8b38e16c04be4b47f7d7c0e6b39afd728e4f1e6e2fffcc",
"image.name": "ghcr.io/graphql-hive/storage:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/storage:wip_organization_access_tokens-arm64"
},
"stripe-billing": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/ztm6df30fuc5whyi8k11aukk3",
"containerimage.config.digest": "sha256:e92c4c662838044b10ffef2569161d967ebe93634059120fef205e47706911da",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:8f709842010ecd57a7f709c7e37ade57b849c05dd6781fd9d4a37edaf571194a",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:8f709842010ecd57a7f709c7e37ade57b849c05dd6781fd9d4a37edaf571194a",
"image.name": "ghcr.io/graphql-hive/stripe-billing:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/stripe-billing:wip_organization_access_tokens-arm64"
},
"tokens": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/xvslgoacmd8piflc543gwy2w7",
"containerimage.config.digest": "sha256:b95761f97a3e233e989f7a2828e3846dd95051bb940ed196cdd32fd7862c4618",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:60e5da36435cf1acbba1ec2c6872b52fe9a5d63c097a8c80b86f1e0baa9e835f",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:60e5da36435cf1acbba1ec2c6872b52fe9a5d63c097a8c80b86f1e0baa9e835f",
"image.name": "ghcr.io/graphql-hive/tokens:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/tokens:wip_organization_access_tokens-arm64"
},
"usage": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/t3tmdmcm42scb63z62invhwex",
"containerimage.config.digest": "sha256:20aa814f5c7b9a51d1daf320756c6cd5c3b86243abdec335dc86b71c5f6d0fcf",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:4f9806c4c8b6de34ee1ffba1b239e55977c36f0efc48177587ccb5b1b737ad33",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:4f9806c4c8b6de34ee1ffba1b239e55977c36f0efc48177587ccb5b1b737ad33",
"image.name": "ghcr.io/graphql-hive/usage:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/usage:wip_organization_access_tokens-arm64"
},
"usage-estimator": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/v78vse5eiy6v4mncl5ptc4hc5",
"containerimage.config.digest": "sha256:3948e584cc38d49e0cd8df6cd2fb5424beb614faadd89d177d780f6322a579f9",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:324972fc696d540e4da6f6afb094a0a9e4af363cc204cb718e8a527bd586fe67",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:324972fc696d540e4da6f6afb094a0a9e4af363cc204cb718e8a527bd586fe67",
"image.name": "ghcr.io/graphql-hive/usage-estimator:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/usage-estimator:wip_organization_access_tokens-arm64"
},
"usage-ingestor": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/cnhz3sr4wu7nz7vd32h5ljr97",
"containerimage.config.digest": "sha256:abf5eec56d25ad4b7b27d950efc4164a20bbaf95bdb23374d784b37466e2a357",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:d0a98df163c4f82b24ab012880d3739e47060a86b829472113e99cfff6caa10a",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:d0a98df163c4f82b24ab012880d3739e47060a86b829472113e99cfff6caa10a",
"image.name": "ghcr.io/graphql-hive/usage-ingestor:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/usage-ingestor:wip_organization_access_tokens-arm64"
},
"webhooks": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/node@22.13.0-slim?platform=linux%2Farm64",
"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": "1ff10816d44ee474c802b10c555435fe75f98016",
"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": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:dockerfile": "xerowlb9b6lm8x6mj03utdlls",
"local-sessionid:shared": "xerowlb9b6lm8x6mj03utdlls"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-fce81dbe-7ae6-4180-89da-ac73c7f8d846/builder-fce81dbe-7ae6-4180-89da-ac73c7f8d8460/idq3blt6g2wtxzl91ptq6uxts",
"containerimage.config.digest": "sha256:668d5861341a0264a975ba66c0eb9469384470aa0898bbb621e4634c0f929966",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:4d677d989afc3e74269c63392337d90189f96cafa6cf83e5dfbbc6b6a6bb25b2",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:4d677d989afc3e74269c63392337d90189f96cafa6cf83e5dfbbc6b6a6bb25b2",
"image.name": "ghcr.io/graphql-hive/webhooks:1ff10816d44ee474c802b10c555435fe75f98016-arm64,ghcr.io/graphql-hive/webhooks:wip_organization_access_tokens-arm64"
}
} |
d1be7ea
to
66165f3
Compare
f258b53
to
58fc5bf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic here is shared between organization members and organization access tokens, so I moved it form the organization members to this new shared file.
await this.session.assertPerformAction({ | ||
action: 'schema:loadFromRegistry', | ||
action: 'project:describe', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
schema:loadFromRegistry
is too specific. Instead ,it should be project:describe
access that must be granted to the access token. Since we do not expose the permission to the outside world, this change is safe to perform.
+ "./build/src/drivers/redis": "./build/src/drivers/redis.js", | ||
+ "./build/src/drivers/memory": "./build/src/drivers/memory.js", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have an esm <-> ts module resolution conflict. Adding these files to the exports map unblocked me from importing the modules without typescript errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost all changes here are related to moving the resource assignment logic to a new standalone file providers/resource-assignments.ts
/** | ||
* Resolved resource groups, used for runtime permission checks. | ||
* Resolved policy statements | ||
*/ | ||
resolvedResources: ResolvedResourceAssignments; | ||
authorizationPolicyStatements: AuthorizationPolicyStatement[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is not related to moving resource assignment logic to a different file.
I reduced the complexity here a bit. Before we created the ResolvedResourceAssignments
object which we transformed to AuthorizationPolicyStatement
within auth/lib/supertokens-strategy.ts
.
Now we already do that here (lazily using a getter function).
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🔭 Outside diff range comments (1)
packages/services/api/src/modules/organization/lib/organization-member-permissions.ts (1)
124-127
:⚠️ Potential issueFix incorrect permission description.
The description for 'project:delete' permission is incorrect. It currently states "Member can access the specified projects" which should describe the deletion capability instead.
Apply this diff to fix the description:
- description: 'Member can access the specified projects.', + description: 'Member can delete the specified projects.',
🧹 Nitpick comments (18)
packages/services/api/src/modules/auth/lib/organization-access-token-strategy.ts (1)
43-99
: Consider caching token verification
You have a// TODO: we should probably cache this verification
. Implementing a short-lived cache for token verification results can reduce repeated cryptographic operations and improve performance, especially if multiple requests use the same token.packages/services/api/src/modules/organization/providers/organization-access-tokens.ts (2)
25-37
: Consider expanding allowed characters
TitleInputModel
uses[ a-zA-Z0-9_-]+
. If you anticipate titles with international characters or user-defined naming, consider relaxing or extending this regex. Otherwise, this is fine for a strictly limited input set.
38-68
: Validate 'createdAt' more strictly
Currently'createdAt'
is validated as a simple string. For stronger guarantees, considerz.string().datetime()
or a refinement to ensure it matches a predictable format (e.g., ISO 8601).packages/services/api/src/modules/organization/providers/organization-members.ts (2)
40-43
: Doc comment accurately explains the new field
Providing context forauthorizationPolicyStatements
clarifies how resolved policies fit into membership. Consider elaborating on whether it’s stored in memory only or persisted elsewhere.
133-145
: On-demand resource resolution
This getter dynamically computes policy statements. If performance becomes an issue, consider memoizing the result within the same session or membership object.packages/services/api/src/modules/organization/module.graphql.ts (2)
51-82
: Consider using an enum for permissions.Currently,
permissions: [String!]!
is free-form. Using an enum instead would help prevent undefined permission strings and provide stricter validation.
107-108
: Harmonize error details.For consistency with other error types that include detailed fields, consider adding an optional
details
property if additional debugging info is needed.packages/services/api/src/modules/organization/providers/resource-assignments.ts (2)
88-183
: Ensure logging and monitoring around database lookups.The constructor and class scaffolding look fine. However, multiple calls to
storage.findProjectsByIds
can become performance hotspots. Monitor or cache as needed.
479-513
: Ensure stable resource identifier format.The
toResourceIdentifier
method is well structured. Keep an eye on future expansions in resource hierarchy, as it may affect the HRN scheme.packages/services/api/src/modules/organization/lib/permissions.ts (1)
3-10
: Well-defined PermissionRecord.Fields like
dependsOn
andwarning
provide flexibility for advanced permission handling. Just confirm thatisReadyOnly
is spelled correctly / intended as “read-only.”packages/services/api/src/modules/organization/lib/organization-access-key.ts (2)
61-75
: Enhance secret generation robustness.While the current implementation is secure, consider using a more robust secret generation approach.
Apply this diff to enhance secret generation:
export async function create(id: string) { - const secret = Crypto.createHash('sha256') - .update(Crypto.randomBytes(20).toString()) - .digest('hex'); + const secret = Crypto.randomBytes(32).toString('base64url'); const hash = await bcrypt.hash(secret, await bcrypt.genSalt()); const privateAccessToken = encode(id, secret); const firstCharacters = privateAccessToken.substr(0, 10); return { privateAccessToken, hash, firstCharacters, }; }
21-21
: Improve error message specificity.The current error message "Invalid access token" could be more specific about what exactly is invalid.
Apply this diff to provide more specific error messages:
-const decodeError = { type: 'error' as const, reason: 'Invalid access token.' }; +function createError(reason: string) { + return { type: 'error' as const, reason }; +} export function decode( accessToken: string, ): { type: 'error'; reason: string } | { type: 'ok'; accessKey: DecodedAccessKey } { if (!accessToken.startsWith(keyPrefix)) { - return decodeError; + return createError('Invalid token prefix. Expected "hvo1/".'); } accessToken = accessToken.slice(keyPrefix.length); let str: string; try { str = globalThis.atob(accessToken); } catch (error) { - return decodeError; + return createError('Invalid base64 encoding.'); } const parts = str.split(':'); if (parts.length > 2) { - return decodeError; + return createError('Invalid token format. Too many segments.'); } const id = parts.at(0); const privateKey = parts.at(1); if (id && privateKey) { return { type: 'ok', accessKey: { id, privateKey } } as const; } - return decodeError; + return createError('Invalid token format. Missing required segments.'); }Also applies to: 28-59
packages/services/api/src/modules/organization/providers/organization-access-tokens-cache.ts (1)
29-43
: Consider making cache configuration more configurable.The cache configuration values (maxItems, TTL, grace period) are hardcoded. Consider making these configurable through environment variables or configuration files.
Apply this diff to make the configuration more flexible:
+const CACHE_CONFIG = { + maxItems: process.env.CACHE_MAX_ITEMS ? parseInt(process.env.CACHE_MAX_ITEMS, 10) : 10_000, + ttl: process.env.CACHE_TTL || '5min', + grace: process.env.CACHE_GRACE || '24h', + prefix: 'bentocache:organization-access-tokens', +}; constructor( @Inject(REDIS_INSTANCE) redis: Redis, @Inject(PG_POOL_CONFIG) pool: DatabasePool, logger: Logger, ) { this.findById = findById({ pool, logger }); this.cache = new BentoCache({ default: 'organizationAccessTokens', stores: { organizationAccessTokens: bentostore() .useL1Layer( memoryDriver({ - maxItems: 10_000, - prefix: 'bentocache:organization-access-tokens', + maxItems: CACHE_CONFIG.maxItems, + prefix: CACHE_CONFIG.prefix, }), ) .useL2Layer( redisDriver({ connection: redis, - prefix: 'bentocache:organization-access-tokens' + prefix: CACHE_CONFIG.prefix }), ), }, }); }integration-tests/tests/api/organization-access-tokens.spec.ts (3)
51-81
: Consider adding more assertions for the success case.While the test verifies the basic success case, consider adding assertions for:
- The format of the generated
privateAccessKey
- The format of the generated
id
- The timestamp format and range of
createdAt
94-95
: Consider using a more descriptive test title.The title "a access token" could be more descriptive, e.g., "Test Access Token" or "Integration Test Token".
Also applies to: 126-127
177-223
: Consider testing additional permission combinations.The test only verifies
organization:describe
andproject:describe
permissions. Consider testing:
- Different permission combinations
- Edge cases with minimal and maximal permissions
- Invalid permission strings
packages/services/storage/src/db/types.ts (1)
159-169
: Consider adding JSDoc comments for the interface.Adding documentation for the interface and its fields would improve code maintainability.
+/** + * Represents an organization access token in the database. + */ export interface organization_access_tokens { + /** The unique identifier of the token */ id: string; + /** The organization this token belongs to */ organization_id: string; + /** When the token was created */ created_at: Date; + /** User-provided title for the token */ title: string; + /** User-provided description for the token */ description: string; + /** List of permissions granted to this token */ permissions: Array<string>; + /** Resources this token has access to */ assigned_resources: any | null; + /** Hash of the token for validation */ hash: string | null; + /** First few characters of the token for display */ first_characters: string | null; }packages/services/api/src/modules/auth/lib/authz.ts (1)
371-371
: Consider documenting the purpose ofusage:report
permission.The new
usage:report
permission's purpose and scope should be documented for clarity.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (33)
integration-tests/tests/api/organization-access-tokens.spec.ts
(1 hunks)package.json
(1 hunks)packages/migrations/src/actions/2025.01.30T00-02-03.organization-access-tokens.ts
(1 hunks)packages/migrations/src/run-pg-migrations.ts
(1 hunks)packages/services/api/package.json
(1 hunks)packages/services/api/src/modules/auth/lib/authz.ts
(2 hunks)packages/services/api/src/modules/auth/lib/organization-access-token-strategy.ts
(1 hunks)packages/services/api/src/modules/auth/lib/supertokens-strategy.ts
(2 hunks)packages/services/api/src/modules/auth/lib/target-access-token-strategy.ts
(0 hunks)packages/services/api/src/modules/auth/module.graphql.mappers.ts
(1 hunks)packages/services/api/src/modules/organization/index.ts
(2 hunks)packages/services/api/src/modules/organization/lib/organization-access-key.ts
(1 hunks)packages/services/api/src/modules/organization/lib/organization-access-token-permissions.ts
(1 hunks)packages/services/api/src/modules/organization/lib/organization-member-permissions.ts
(4 hunks)packages/services/api/src/modules/organization/lib/permissions.ts
(1 hunks)packages/services/api/src/modules/organization/module.graphql.mappers.ts
(2 hunks)packages/services/api/src/modules/organization/module.graphql.ts
(2 hunks)packages/services/api/src/modules/organization/providers/organization-access-tokens-cache.ts
(1 hunks)packages/services/api/src/modules/organization/providers/organization-access-tokens.ts
(1 hunks)packages/services/api/src/modules/organization/providers/organization-manager.ts
(3 hunks)packages/services/api/src/modules/organization/providers/organization-members.ts
(3 hunks)packages/services/api/src/modules/organization/providers/resource-assignments.spec.ts
(1 hunks)packages/services/api/src/modules/organization/providers/resource-assignments.ts
(1 hunks)packages/services/api/src/modules/organization/resolvers/Member.ts
(2 hunks)packages/services/api/src/modules/organization/resolvers/Mutation/createOrganizationAccessToken.ts
(1 hunks)packages/services/api/src/modules/organization/resolvers/Mutation/deleteOrganizationAccessToken.ts
(1 hunks)packages/services/api/src/modules/organization/resolvers/Organization.ts
(3 hunks)packages/services/api/src/modules/organization/resolvers/OrganizationAccessToken.ts
(1 hunks)packages/services/api/src/modules/schema/providers/schema-manager.ts
(2 hunks)packages/services/api/src/modules/shared/providers/id-translator.ts
(2 hunks)packages/services/server/src/index.ts
(2 hunks)packages/services/storage/src/db/types.ts
(2 hunks)patches/bentocache.patch
(1 hunks)
💤 Files with no reviewable changes (1)
- packages/services/api/src/modules/auth/lib/target-access-token-strategy.ts
✅ Files skipped from review due to trivial changes (2)
- package.json
- packages/services/api/src/modules/organization/providers/resource-assignments.spec.ts
🧰 Additional context used
📓 Path-based instructions (2)
`packages/services/**`: Microservices written in NodeJS and ...
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.
Thecdn-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/package.json
packages/services/api/src/modules/organization/resolvers/OrganizationAccessToken.ts
packages/services/storage/src/db/types.ts
packages/services/api/src/modules/organization/resolvers/Mutation/deleteOrganizationAccessToken.ts
packages/services/api/src/modules/organization/providers/organization-manager.ts
packages/services/api/src/modules/organization/providers/organization-access-tokens-cache.ts
packages/services/api/src/modules/auth/lib/authz.ts
packages/services/api/src/modules/organization/resolvers/Member.ts
packages/services/api/src/modules/organization/module.graphql.mappers.ts
packages/services/api/src/modules/schema/providers/schema-manager.ts
packages/services/api/src/modules/auth/module.graphql.mappers.ts
packages/services/api/src/modules/organization/resolvers/Mutation/createOrganizationAccessToken.ts
packages/services/api/src/modules/organization/lib/organization-access-token-permissions.ts
packages/services/api/src/modules/organization/resolvers/Organization.ts
packages/services/api/src/modules/organization/index.ts
packages/services/api/src/modules/auth/lib/supertokens-strategy.ts
packages/services/api/src/modules/organization/lib/organization-member-permissions.ts
packages/services/api/src/modules/organization/lib/permissions.ts
packages/services/api/src/modules/organization/lib/organization-access-key.ts
packages/services/api/src/modules/organization/providers/organization-members.ts
packages/services/server/src/index.ts
packages/services/api/src/modules/auth/lib/organization-access-token-strategy.ts
packages/services/api/src/modules/shared/providers/id-translator.ts
packages/services/api/src/modules/organization/providers/resource-assignments.ts
packages/services/api/src/modules/organization/module.graphql.ts
packages/services/api/src/modules/organization/providers/organization-access-tokens.ts
`integration-tests/**`: integration tests for ensuring featu...
integration-tests/**
: integration tests for ensuring features and important flows are running. Usually, changes to thepackages/
directory will affect this. In ideal flow, each PR should include integration tests.
integration-tests/tests/api/organization-access-tokens.spec.ts
🔇 Additional comments (48)
packages/services/api/src/modules/auth/lib/organization-access-token-strategy.ts (4)
1-5
: No issues with initial imports
These imports are straightforward and appropriate for the module’s functionality.
7-30
: Session extension logic looks solid
OrganizationAccessTokenSession
nicely extendsSession
. The overriddenloadPolicyStatementsForOrganization
method returns statically assigned policies, which is fine as long as the session remains short-lived or policy changes are infrequent.
32-36
: Class definition is coherent
OrganizationAccessTokenStrategy
extendsAuthNStrategy
with a clear type parameter. Storinglogger
andcache
as private fields is good practice.
37-41
: Constructor usage
Acceptingdeps
as a single object is a neat approach for dependency injection. Creates a well-scoped logger child for this strategy.packages/services/api/src/modules/organization/providers/organization-access-tokens.ts (3)
93-174
: Creation flow appears robust
Thecreate
method handles input validation (title, description), checks permissions, and stores the new token. It returns a structured success or error object. The approach is consistent and modular. Consider wrapping everything in a transaction if you plan on adding more DB actions in a single operation later.
176-202
: Properly checks permissions before deleting
Thedelete
method ensures the record exists, verifies permissions, removes the entry, and purges from cache. This is a good pattern for consistent resource cleanup.
209-251
: Straightforward retrieval with logging
findById
correctly validates the ID as UUID, retrieves the token, parses it through the Zod model, and logs relevant details. Returningnull
if nothing is found is clear and easy to handle.packages/services/api/src/modules/organization/providers/organization-members.ts (2)
4-6
: Imports are well chosen
Addingtype Organization
andAuthorizationPolicyStatement
helps clarify usage without over-importing.
10-15
: Sound modular approach
Using theresource-assignments
module promotes better separation of concerns. This should simplify maintenance and future enhancements.packages/services/api/src/modules/organization/module.graphql.ts (5)
38-44
: Consider validating input arguments.The new mutations appear correct overall, but ensure proper input validation for security and consistency.
46-49
: Verify one-of directive usage.Confirm that
@oneOf
is recognized and validated in your GraphQL setup to ensure that exactly one field is used.
85-92
: Looks good.The
OrganizationAccessToken
type is consistent with the creation input.
94-105
: Straightforward deletion schema.The input and result types for deleting an organization access token appear clearly defined.
318-321
: Confirm resolver implementation.Ensure that your resolver or data loader populates
availableOrganizationPermissionGroups
correctly. Consider handling edge cases when no permissions exist.packages/services/api/src/modules/organization/providers/resource-assignments.ts (6)
1-37
: Validate domain logic for assignment modes.Your Zod schemas for wildcard vs. granular modes look well-structured. Ensure consistent handling throughout your codebase where these modes are interpreted.
38-87
: Check for performance in nested loops.Union-based assignments (e.g.,
AssignedServicesModel
) are quite flexible. Bear in mind that nested transformations can be costly if used frequently. Consider caching or batching in higher call volumes.
185-324
: Comprehensive resource filtering.The logic to filter out non-existent or non-org-bound Projects/Targets is essential for preventing privilege escalation. Great job. Ensure thorough testing of edge cases.
327-329
: Small utility isSome.The
isSome
function is concise and effective. No issues here.
365-473
: Very clear resource resolution.
resolveResourceAssignment
correctly handles wildcard expansions. Validate that front-end or other callers handle the varying data structures (arrays vs. single object).
515-563
: Check for missing policies.
translateResolvedResourcesToAuthorizationPolicyStatements
allows for dynamic policy generation. Verify that each permission group is tested to avoid overlooked actions.packages/services/api/src/modules/organization/lib/permissions.ts (1)
12-16
: PermissionGroup structure is clear.The grouping logic is solid. Ensure the UI or relevant clients properly render nested permissions if needed.
patches/bentocache.patch (1)
9-10
: LGTM! The additional export mappings resolve module resolution conflicts.The new export mappings provide alternative paths for accessing the Redis and memory drivers, which aligns with the existing exports and resolves the ESM <-> TS module resolution conflict.
packages/services/api/src/modules/organization/module.graphql.mappers.ts (1)
6-6
: LGTM! The new access token mapper follows established patterns.The addition of
OrganizationAccessTokenMapper
is consistent with the existing mapper types and aligns with the PR's objective of introducing organization access tokens.Also applies to: 17-17
packages/migrations/src/actions/2025.01.30T00-02-03.organization-access-tokens.ts (1)
18-22
: LGTM! Index optimization looks good.The composite index on (organization_id, created_at DESC, id DESC) is well-designed for:
- Filtering by organization
- Sorting by creation date
- Ensuring deterministic ordering with id
packages/services/api/src/modules/organization/index.ts (1)
16-23
: Verify provider dependency order.The order of providers in the array matters for dependency injection. Ensure that providers are listed in the correct dependency order, with base providers (those with no dependencies) first, followed by providers that depend on them.
Run this script to analyze provider dependencies:
✅ Verification successful
🏁 Script executed:
#!/bin/bash # Description: Check provider dependencies by searching for injector.get() calls echo "Analyzing provider dependencies..." # Search for dependencies in OrganizationAccessTokens echo -e "\nDependencies of OrganizationAccessTokens:" ast-grep --pattern 'injector.get($_)' packages/services/api/src/modules/organization/providers/organization-access-tokens.ts # Search for dependencies in OrganizationAccessTokensCache echo -e "\nDependencies of OrganizationAccessTokensCache:" ast-grep --pattern 'injector.get($_)' packages/services/api/src/modules/organization/providers/organization-access-tokens-cache.ts # Search for dependencies in ResourceAssignments echo -e "\nDependencies of ResourceAssignments:" ast-grep --pattern 'injector.get($_)' packages/services/api/src/modules/organization/providers/resource-assignments.tsLength of output: 756
Provider Dependency Order Verified
Based on the dependency analysis, none of the providers—specifically OrganizationAccessTokens, OrganizationAccessTokensCache, and ResourceAssignments—contain anyinjector.get(…)
calls that indicate inter-provider dependencies. This suggests that there is no imposed ordering required for dependency injection in this module, and the current order is acceptable.packages/services/api/src/modules/organization/resolvers/Mutation/createOrganizationAccessToken.ts (2)
15-23
: LGTM! Success case is well-handled.The success case properly structures the response with the created token and private access key.
25-31
: LGTM! Error case is well-structured.The error case properly includes both a message and details for better error handling by clients.
packages/services/api/src/modules/organization/resolvers/Member.ts (1)
3-3
: LGTM! Good refactoring towards granular resource-based access control.The changes align well with the PR's objective of implementing more granular resource-based access control. The modification to use
ResourceAssignments
and pass specific properties instead of the entire member object is a good practice.Also applies to: 38-43
packages/services/api/src/modules/organization/lib/organization-access-token-permissions.ts (1)
65-67
: LGTM! Good use of Set for unique permissions.Using Set with flatMap is an elegant way to ensure unique permission IDs across all groups.
packages/services/api/src/modules/organization/lib/organization-access-key.ts (1)
1-79
: LGTM! Secure implementation with proper error handling.The implementation uses appropriate cryptographic functions, proper error handling, and secure token generation. The use of bcrypt for hashing is a good security practice.
packages/services/api/src/modules/organization/providers/organization-access-tokens-cache.ts (1)
46-68
: LGTM! Well-implemented caching with proper TTL and grace period.The implementation uses a two-layer caching strategy with proper TTL and grace period. The methods are concise and focused.
packages/services/api/src/modules/organization/resolvers/Organization.ts (2)
2-3
: LGTM! Clean import refactoring.The imports have been cleanly split into separate modules for organization access token permissions and member permissions, improving code organization.
12-12
: LGTM! Well-structured permission group resolver.The new resolver
availableOrganizationPermissionGroups
follows the same pattern asavailableMemberPermissionGroups
, maintaining consistency in the codebase.Also applies to: 187-192
packages/services/api/src/modules/auth/lib/supertokens-strategy.ts (1)
93-93
: LGTM! Simplified policy statement loading.The change reduces complexity by directly using the policy statements from the assigned role, making the code more maintainable.
packages/services/api/src/modules/shared/providers/id-translator.ts (1)
160-210
: LGTM! Well-implemented organization reference resolver.The new
resolveOrganizationReference
method:
- Follows consistent error handling patterns
- Includes comprehensive debug logging
- Handles both selector and ID-based references
packages/services/api/src/modules/organization/lib/organization-member-permissions.ts (1)
269-270
: LGTM! New permissions for organization access tokens.The addition of 'accessToken:modify' and 'usage:report' permissions aligns with the PR objectives of introducing organization access tokens.
integration-tests/tests/api/organization-access-tokens.spec.ts (2)
6-49
: LGTM! Well-structured GraphQL operations.The GraphQL operations are well-defined with appropriate fields for both mutation and query operations.
225-273
: LGTM! Thorough negative test case.The test effectively validates that granular resource access control works as expected.
packages/migrations/src/run-pg-migrations.ts (1)
161-161
: LGTM! Migration properly added to the sequence.The new migration is correctly added at the end of the migrations list.
packages/services/api/src/modules/auth/lib/authz.ts (2)
352-352
: LGTM! New permission aligns with feature scope.The
accessToken:modify
permission is appropriately added to the organization level permissions.
386-392
: Verify the impact of permission changes.The changes to permissions might affect existing roles and access patterns.
❌ Verification inconclusive
🏁 Script executed:
#!/bin/bash # Description: Check for existing usage of removed/modified permissions # Check for usage of schema:loadFromRegistry permission rg -l "schema:loadFromRegistry" # Check for existing roles that might be affected ast-grep --pattern 'permissions: [$_]'Length of output: 72
Permission Impact Review – Manual Verification Recommended
The automated checks did not reveal any usage of the
schema:loadFromRegistry
permission or references within role definitions. However, since no output was returned from the search command, it’s advisable to perform a manual review to ensure that no dynamic or indirect usages have been overlooked.packages/services/api/package.json (1)
47-47
: Verify the bentocache version and security advisories.The new dependency
bentocache
is pinned to version 1.1.0. Let's verify this version is secure and up-to-date.✅ Verification successful
🏁 Script executed:
#!/bin/bash # Description: Check for security advisories and latest versions of the `bentocache` library. # Check NPM for latest versions curl -s https://registry.npmjs.org/bentocache | jq '.["dist-tags"].latest' # Check for security advisories gh api graphql -f query=' { securityVulnerabilities(first: 5, ecosystem: NPM, package: "bentocache") { nodes { advisory { summary severity publishedAt } vulnerableVersionRange firstPatchedVersion { identifier } } } }'Length of output: 428
Bentocache version 1.1.0 is verified as secure.
- The NPM registry confirms that 1.1.0 is the latest version.
- No security advisories were found in the GitHub security query.
packages/services/server/src/index.ts (2)
58-61
: LGTM! New imports for organization access token support.The imports are correctly organized and follow the module structure.
421-425
: LGTM! New organization access token strategy implementation.The strategy is correctly configured with logger and cache dependencies.
packages/services/api/src/modules/organization/providers/organization-manager.ts (3)
23-23
: LGTM! New import for resource assignments.The import is correctly placed with other organization-related imports.
48-48
: LGTM! New resource assignments dependency.The dependency is correctly injected and follows the established pattern.
1007-1010
: LGTM! Updated resource assignment transformation.The implementation correctly uses the new
resourceAssignments
service.packages/services/api/src/modules/schema/providers/schema-manager.ts (1)
999-1010
: LGTM! Permission change fromschema:loadFromRegistry
toproject:describe
.The permission change aligns with the previous feedback and is safe as the permission is not exposed externally.
export const deleteOrganizationAccessToken: NonNullable< | ||
MutationResolvers['deleteOrganizationAccessToken'] | ||
> = async (_parent, args, { injector }) => { | ||
const result = await injector.get(OrganizationAccessTokens).delete({ | ||
organizationAccessTokenId: args.input.organizationAccessTokenId, | ||
}); | ||
|
||
return { | ||
ok: { | ||
__typename: 'DeleteOrganizationAccessTokenResultOk', | ||
deletedOrganizationAccessTokenId: result.organizationAccessTokenId, | ||
}, | ||
}; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling for token deletion failures.
While the resolver is well-structured, it should handle potential errors that might occur during token deletion (e.g., token not found, permission issues).
Consider adding try-catch block and error result:
export const deleteOrganizationAccessToken: NonNullable<
MutationResolvers['deleteOrganizationAccessToken']
> = async (_parent, args, { injector }) => {
+ try {
const result = await injector.get(OrganizationAccessTokens).delete({
organizationAccessTokenId: args.input.organizationAccessTokenId,
});
return {
ok: {
__typename: 'DeleteOrganizationAccessTokenResultOk',
deletedOrganizationAccessTokenId: result.organizationAccessTokenId,
},
};
+ } catch (error) {
+ return {
+ error: {
+ __typename: 'DeleteOrganizationAccessTokenResultError',
+ message: error instanceof Error ? error.message : 'Failed to delete token',
+ },
+ };
+ }
};
📝 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.
export const deleteOrganizationAccessToken: NonNullable< | |
MutationResolvers['deleteOrganizationAccessToken'] | |
> = async (_parent, args, { injector }) => { | |
const result = await injector.get(OrganizationAccessTokens).delete({ | |
organizationAccessTokenId: args.input.organizationAccessTokenId, | |
}); | |
return { | |
ok: { | |
__typename: 'DeleteOrganizationAccessTokenResultOk', | |
deletedOrganizationAccessTokenId: result.organizationAccessTokenId, | |
}, | |
}; | |
}; | |
export const deleteOrganizationAccessToken: NonNullable< | |
MutationResolvers['deleteOrganizationAccessToken'] | |
> = async (_parent, args, { injector }) => { | |
try { | |
const result = await injector.get(OrganizationAccessTokens).delete({ | |
organizationAccessTokenId: args.input.organizationAccessTokenId, | |
}); | |
return { | |
ok: { | |
__typename: 'DeleteOrganizationAccessTokenResultOk', | |
deletedOrganizationAccessTokenId: result.organizationAccessTokenId, | |
}, | |
}; | |
} catch (error) { | |
return { | |
error: { | |
__typename: 'DeleteOrganizationAccessTokenResultError', | |
message: | |
error instanceof Error ? error.message : 'Failed to delete token', | |
}, | |
}; | |
} | |
}; |
PermissionGroup, | ||
PermissionRecord, | ||
} from '../organization/lib/organization-member-permissions'; | ||
import { PermissionGroup, PermissionRecord } from '../organization/lib/permissions'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify the impact of permissions module restructuring.
The import path change reflects a reorganization of the permissions module. Ensure that all references to these types have been updated consistently across the codebase.
Run the following script to verify the usage of the old import path:
🏁 Script executed:
#!/bin/bash
# Description: Check for any remaining references to the old permissions path.
rg -l "organization-member-permissions" --type ts
Length of output: 208
I'll now run a script to print the surrounding lines of the "organization-member-permissions" references in the two files. This will help determine whether these references need updating in line with the module reorganization.
🏁 Script executed:
#!/bin/bash
echo "=== organization-member-roles.ts ==="
rg -C 3 "organization-member-permissions" packages/services/api/src/modules/organization/providers/organization-member-roles.ts
echo ""
echo "=== Organization.ts ==="
rg -C 3 "organization-member-permissions" packages/services/api/src/modules/organization/resolvers/Organization.ts
Length of output: 1226
Based on the search results:
- The new file in
packages/services/api/src/modules/auth/module.graphql.mappers.ts
now imports from:
../organization/lib/permissions
- However, two other files still import from the legacy path (via the term “organization-member-permissions”):
•packages/services/api/src/modules/organization/providers/organization-member-roles.ts
•packages/services/api/src/modules/organization/resolvers/Organization.ts
To decide if this is an issue, we must confirm whether these two imports should have migrated to the new path as well. The review comment requests verifying that all references were updated, meaning that if a module’s internal reorganization calls for a singular updated location, then legacy paths should not be present. The fact that “organization-member-permissions” is still referenced in parts of the organization module shows inconsistency compared to the new permissions import used in the auth module.
Actionable Points:
- Verify if
../organization/lib/permissions
is now the canonical location for all permissions-related types.
If so, then the usage of../lib/organization-member-permissions
in the organization providers and resolvers should be updated accordingly. - Update the import paths in
organization-member-roles.ts
andOrganization.ts
to use the new location if the reorganization mandates a single source for permissions types.
Thus, the evidence indicates that some references to permissions-related code have not been updated consistently.
Recommendation:
Review and, if needed, refactor the imports from ../lib/organization-member-permissions
in the listed organization module files to align with the new module reorganization.
packages/migrations/src/actions/2025.01.30T00-02-03.organization-access-tokens.ts
Show resolved
Hide resolved
resources: async (accessToken, _arg, { injector }) => { | ||
return injector.get(ResourceAssignments).resolveGraphQLMemberResourceAssignment({ | ||
organizationId: accessToken.organizationId, | ||
resources: accessToken.assignedResources, | ||
}); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling for resource resolution.
The resolver should handle potential errors from resolveGraphQLMemberResourceAssignment
to prevent unhandled promise rejections.
Apply this diff to add error handling:
resources: async (accessToken, _arg, { injector }) => {
- return injector.get(ResourceAssignments).resolveGraphQLMemberResourceAssignment({
- organizationId: accessToken.organizationId,
- resources: accessToken.assignedResources,
- });
+ try {
+ return await injector.get(ResourceAssignments).resolveGraphQLMemberResourceAssignment({
+ organizationId: accessToken.organizationId,
+ resources: accessToken.assignedResources,
+ });
+ } catch (error) {
+ console.error('Failed to resolve resources:', error);
+ return null; // or handle error appropriately based on your GraphQL schema
+ }
},
📝 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.
resources: async (accessToken, _arg, { injector }) => { | |
return injector.get(ResourceAssignments).resolveGraphQLMemberResourceAssignment({ | |
organizationId: accessToken.organizationId, | |
resources: accessToken.assignedResources, | |
}); | |
}, | |
resources: async (accessToken, _arg, { injector }) => { | |
try { | |
return await injector.get(ResourceAssignments).resolveGraphQLMemberResourceAssignment({ | |
organizationId: accessToken.organizationId, | |
resources: accessToken.assignedResources, | |
}); | |
} catch (error) { | |
console.error('Failed to resolve resources:', error); | |
return null; // or handle error appropriately based on your GraphQL schema | |
} | |
}, |
...es/services/api/src/modules/organization/resolvers/Mutation/createOrganizationAccessToken.ts
Show resolved
Hide resolved
packages/services/api/src/modules/organization/lib/organization-access-token-permissions.ts
Show resolved
Hide resolved
@@ -158,5 +158,6 @@ export const runPGMigrations = async (args: { slonik: DatabasePool; runTo?: stri | |||
await import('./actions/2025.01.17T10-08-00.drop-activities'), | |||
await import('./actions/2025.01.20T00-00-00.legacy-registry-model-removal'), | |||
await import('./actions/2025.01.30T00-00-00.granular-member-role-permissions'), | |||
await import('./actions/2025.01.30T00-02-03.organization-access-tokens'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: update dates
z.literal('schema:compose'), | ||
z.literal('usage:report'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: remove for now; will introduce it when we implement organization access token support in usage reporting service
); | ||
|
||
const permissions = Array.from( | ||
new Set(args.permissions.filter(permission => assignablePermissions.has(permission as any))), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: any cast
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: implement Organization.accessTokens
field
Background
Adds organization access tokens which will supersede target access tokens.
Organization access tokens allow selecting scopes and permissions, allowing granular resource-based access control.
Description
This PR introduces the CRUD parts for creating, updating, and deleting organization access tokens.
Checklist