-
Notifications
You must be signed in to change notification settings - Fork 109
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
improve(integrations/slack): sentry alert on error #6537
base: main
Are you sure you want to change the base?
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis pull request introduces a structured approach to JSON fetching and error handling by adding a new asynchronous Changes
Sequence Diagram(s)sequenceDiagram
participant Caller
participant fetchJson
participant FetchAPI as "fetch()"
participant JSONParser as "JSON.parse()"
participant ZodValidator as "Zod.safeParse()"
Caller->>fetchJson: Call fetchJson(url, requestInit, schema)
fetchJson->>FetchAPI: Execute fetch(url, requestInit)
alt Fetch network error (TypeError/DOMException)
FetchAPI-->>fetchJson: Return error
fetchJson-->>Caller: Return corresponding FetchJsonRequest* error
else Fetch successful
FetchAPI-->>fetchJson: Return Response
fetchJson->>JSONParser: Parse response as JSON
alt JSON parse error (SyntaxError/TypeError/DOMException)
JSONParser-->>fetchJson: Return error
fetchJson-->>Caller: Return corresponding FetchJsonResponse* error
else JSON parsed successfully
alt Schema provided
fetchJson->>ZodValidator: Validate JSON via safeParse
alt Validation fails
ZodValidator-->>fetchJson: Validation error
fetchJson-->>Caller: Return FetchJsonResponseSchemaError
else Validation succeeds
ZodValidator-->>fetchJson: Return validated data
fetchJson-->>Caller: Return validated JSON data
end
else No schema provided
fetchJson-->>Caller: Return JSON data
end
end
end
sequenceDiagram
participant User
participant Server
participant SlackAPI
participant FetchJson as "fetchJson"
participant Slack as "Slack OAuth Endpoint"
User->>Server: Initiate Slack connect request
Server->>SlackAPI: createOauth2AuthorizeUrl({state, clientId, redirectUrl, scopes})
SlackAPI-->>Server: Return OAuth2 URL
Server->>User: Redirect to OAuth2 URL
User->>Slack: Complete OAuth2 authorization (return code)
Slack->>Server: Provide authorization code via callback
Server->>SlackAPI: requestOauth2Access(payload with code, clientId, clientSecret)
SlackAPI->>FetchJson: POST request to Slack OAuth endpoint
FetchJson-->>SlackAPI: Return JSON response or error
SlackAPI-->>Server: Return OAuth2AccessResult (access token or error)
Server->>User: Finalize connection or report error
Possibly Related PRs
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 (
|
📚 Storybook DeploymentThe latest changes are available as preview in: https://e01e7d34.hive-storybook.pages.dev |
slackResult instanceof FetchJsonErrors.FetchJsonRequestTypeError | ||
) { | ||
const error = new SlackIntegrationErrors.SlackAPIRequestError( | ||
{ organizationId }, | ||
slackResult, | ||
); | ||
Sentry.captureException(error, { | ||
level: 'error', | ||
tags: sentryTagsRouteLevel, | ||
extra: error.context, | ||
}); | ||
throw error; | ||
} | ||
|
||
if (!slackResponseResult.success) { | ||
req.log.error('Error parsing data from Slack API (orgId=%s)', organizationSlug); | ||
req.log.error(slackResponseResult.error.toString()); | ||
void res.status(400).send('Failed to parse the response from Slack API'); | ||
if (slackResult instanceof FetchJsonErrors.FetchJsonResponseError) { | ||
const error = new SlackIntegrationErrors.SlackDefectResponseError( | ||
{ organizationId }, | ||
slackResult, | ||
); | ||
Sentry.captureException(error, { | ||
level: 'warning', | ||
tags: sentryTagsRouteLevel, | ||
extra: { | ||
...error.context, | ||
cause: slackResult.cause.message, | ||
}, | ||
}); | ||
req.log.warn(error.context, error.message); | ||
void res.status(400).send(error.message); | ||
return; | ||
} | ||
|
||
if (!slackResponseResult.data.ok) { | ||
req.log.error('Failed to retrieve access token from Slack API (orgId=%s)', organizationSlug); | ||
req.log.error(slackResponseResult.data.error); | ||
void res.status(400).send(slackResponseResult.data.error); | ||
if (!slackResult.ok) { | ||
const error = new SlackIntegrationErrors.TokenRetrieveError({ | ||
organizationId, | ||
slackErrorMessage: slackResult.error, | ||
}); | ||
Sentry.captureException(error, { | ||
level: 'warning', | ||
tags: sentryTagsRouteLevel, | ||
extra: error.context, | ||
}); | ||
req.log.warn(error.context, error.message); | ||
void res.status(400).send(slackResult.error); | ||
return; | ||
} | ||
|
||
const token = slackResponseResult.data.access_token; | ||
|
||
const result = await graphqlRequest({ | ||
const resultGraphql = await graphqlRequest({ | ||
url: env.graphqlPublicEndpoint, | ||
headers: { | ||
...req.headers, | ||
'content-type': 'application/json', | ||
'graphql-client-name': 'Hive App', | ||
'graphql-client-version': env.release, | ||
}, | ||
operationName: 'SlackIntegration_addSlackIntegration', | ||
document: SlackIntegration_addSlackIntegration, | ||
variables: { | ||
input: { | ||
organizationSlug, | ||
token, | ||
organizationSlug: organizationId, | ||
token: slackResult.access_token, | ||
}, | ||
}, | ||
}); | ||
|
||
if (result.errors) { | ||
req.log.error('Failed setting slack token (orgId=%s)', organizationSlug); | ||
for (const error of result.errors) { | ||
req.log.error(error); | ||
if (resultGraphql.errors) { | ||
const resultGraphqlAggError = new Kit.Errors.TypedAggregateError([...resultGraphql.errors]); | ||
const error = new SlackIntegrationErrors.APIRequestError( | ||
{ organizationId }, | ||
resultGraphqlAggError, | ||
); | ||
req.log.error(error.context, error.message); | ||
// todo: add base error type with contextChain property | ||
for (const errorCause of error.cause.errors) { | ||
req.log.error(errorCause); | ||
} | ||
throw new Error('Failed setting slack token.'); | ||
throw error; | ||
} | ||
|
||
void res.redirect(`/${organizationSlug}/view/settings`); | ||
void res.redirect(`/${organizationId}/view/settings`); | ||
}); |
Check failure
Code scanning / CodeQL
Missing rate limiting High
authorization
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix AI 25 days ago
To fix the problem, we need to introduce rate limiting to the route handler that performs the OAuth2 authorization. The best way to achieve this is by using a rate-limiting middleware. Since the code uses Fastify, we can use the fastify-rate-limit
plugin to limit the number of requests to the /api/slack/callback
endpoint.
- Install the
fastify-rate-limit
plugin. - Register the plugin with the Fastify instance.
- Apply the rate limiting to the specific route handler.
-
Copy modified line R11 -
Copy modified lines R24-R27 -
Copy modified line R41
@@ -10,2 +10,3 @@ | ||
import { graphqlRequest } from './utils'; | ||
import fastifyRateLimit from 'fastify-rate-limit'; | ||
|
||
@@ -22,2 +23,6 @@ | ||
export function connectSlack(server: FastifyInstance) { | ||
server.register(fastifyRateLimit, { | ||
max: 100, // maximum of 100 requests | ||
timeWindow: '15 minutes' // per 15 minutes | ||
}); | ||
// ---------------------------------- | ||
@@ -35,3 +40,3 @@ | ||
|
||
server.get('/api/slack/callback', async (req, res) => { | ||
server.get('/api/slack/callback', { config: { rateLimit: { max: 5, timeWindow: '1 minute' } } }, async (req, res) => { | ||
const sentryTagsRouteLevel = { |
-
Copy modified lines R143-R145
@@ -142,2 +142,5 @@ | ||
] | ||
}, | ||
"dependencies": { | ||
"fastify-rate-limit": "^5.9.0" | ||
} |
Package | Version | Security advisories |
fastify-rate-limit (npm) | 5.9.0 | None |
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 suggestion is interesting. I wonder if we should throttle people eventually..
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: 3
🧹 Nitpick comments (3)
packages/web/app/src/lib/slack-api.ts (1)
64-68
: Consider replacingquerystring.stringify
withURLSearchParams
for improved readability and modern Node.js compatibility.While
querystring
still works, Node.js documentation encourages usingURLSearchParams
as the newer, more standard API. This can simplify migration and keep code consistent with the rest of the file's usage ofURL*
objects.Example snippet:
-body: stringify({ - client_id: payload.clientId, - client_secret: payload.clientSecret, - code: payload.code, -}), +const formData = new URLSearchParams({ + client_id: payload.clientId, + client_secret: payload.clientSecret, + code: payload.code, +}); +body: formData.toString(),packages/web/app/src/lib/kit/helpers.ts (1)
12-23
: Consider optimizing the implementation and improving error messages.The function is well-typed and provides good type safety. However, consider these improvements:
- Use
Array.some()
for a more functional and potentially more efficient implementation.- Include the actual type of the value in the error message for better debugging.
Consider this implementation:
export const oneOf = <type extends readonly unknown[]>( ...guards: OneOfCheck<type> ): ((value: unknown) => type[number]) => { return (value: unknown) => { - for (const guard of guards) { - if (guard(value)) { - return value; - } - } - throw new Error(`Unexpected value received by oneOf: ${value}`); + if (guards.some(guard => guard(value))) { + return value; + } + throw new Error( + `Unexpected value received by oneOf: ${value} (type: ${typeof value})` + ); }; };packages/web/app/src/lib/kit/errors.ts (1)
24-32
: Consider adding utility methods for error aggregation.The
TypedAggregateError
class provides good type safety but could benefit from utility methods for common operations.Consider adding these utility methods:
export class TypedAggregateError<$Error extends Error> extends AggregateError { constructor( public errors: $Error[], message?: string, ) { super(errors, message); this.name = this.constructor.name; } + public hasErrors(): boolean { + return this.errors.length > 0; + } + + public getErrorMessages(): string[] { + return this.errors.map(error => error.message); + } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
packages/web/app/src/lib/fetch-json.ts
(1 hunks)packages/web/app/src/lib/kit/errors.ts
(1 hunks)packages/web/app/src/lib/kit/helpers.ts
(1 hunks)packages/web/app/src/lib/kit/index_.ts
(1 hunks)packages/web/app/src/lib/slack-api.ts
(1 hunks)packages/web/app/src/server/slack.ts
(4 hunks)
✅ Files skipped from review due to trivial changes (1)
- packages/web/app/src/lib/kit/index_.ts
🧰 Additional context used
🪛 Biome (1.9.4)
packages/web/app/src/lib/fetch-json.ts
[error] 78-78: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: typescript / typecheck
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: alpha / cli-artifacts
- GitHub Check: code-style / eslint-and-prettier
🔇 Additional comments (4)
packages/web/app/src/server/slack.ts (3)
64-65
: Potential missing validation for the organization ID.The
state
field is parsed as a generic string and used asorganizationId
. Ensure it's validated (for example, checking existence or matching the expected format) to avoid malicious or invalid values.
185-192
: Scopes delimited by commas increateOauth2AuthorizeUrl
may cause Slack OAuth issues.Because
SlackAPI.createOauth2AuthorizeUrl
currently uses comma-separated scopes, be aware that Slack typically expects them to be space-separated. This may lead to a mismatch in the authorization request unless Slack has changed its format.
201-246
: Solid error-handling approach.The namespace-based error classes provide clear, structured errors. This consistent pattern helps maintain robust error management across the Slack integration.
packages/web/app/src/lib/kit/helpers.ts (1)
25-27
: LGTM!The type alias is well-designed, using TypeScript's mapped types to correctly constrain the guard functions to their corresponding types in the tuple.
}) => { | ||
const url = new URL('https://slack.com/oauth/v2/authorize'); | ||
const searchParams = new URLSearchParams({ | ||
scope: parameters.scopes.join(','), |
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.
Slack scopes should be space-separated instead of comma-separated.
According to Slack's documentation, the scope
parameter expects space-separated scopes rather than comma-separated. Using commas may cause request failures or unexpected behavior.
Apply this diff to fix the scopes parameter:
- scope: parameters.scopes.join(','),
+ scope: parameters.scopes.join(' '),
📝 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.
scope: parameters.scopes.join(','), | |
scope: parameters.scopes.join(' '), |
|
||
export class FetchJsonRequestNetworkError extends Kit.Errors.ContextualError< | ||
'FetchJsonRequestNetworkError', | ||
{}, |
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
Avoid using {}
as a type.
The lint rule recommends replacing {}
with a more explicit shape or Record<string, never>
to avoid implying any non-nullable value.
Proposed fix:
-export class FetchJsonRequestNetworkError extends Kit.Errors.ContextualError<
- 'FetchJsonRequestNetworkError',
- {},
- DOMException
- > {
+export class FetchJsonRequestNetworkError extends Kit.Errors.ContextualError<
+ 'FetchJsonRequestNetworkError',
+ Record<string, never>,
+ DOMException
+> {
📝 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 class FetchJsonRequestNetworkError extends Kit.Errors.ContextualError< | |
'FetchJsonRequestNetworkError', | |
Record<string, never>, | |
DOMException | |
> { | |
// ...rest of the class implementation | |
} |
🧰 Tools
🪛 Biome (1.9.4)
[error] 78-78: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
export abstract class ContextualError< | ||
$Name extends string = string, | ||
$Context extends object = object, | ||
$Cause extends Error | undefined = Error | undefined, | ||
> extends Error { | ||
public name: $Name; | ||
public context: $Context; | ||
public cause: $Cause; | ||
constructor( | ||
...args: undefined extends $Cause | ||
? [context: $Context, cause?: $Cause] | ||
: [context: $Context, cause: $Cause] | ||
) { | ||
const [context, cause] = args; | ||
super('Something went wrong.', { cause }); | ||
this.name = this.constructor.name as $Name; | ||
this.context = context; | ||
this.cause = cause as $Cause; | ||
} | ||
} |
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
Consider enhancing the error message handling.
The ContextualError
class provides a good foundation for contextual errors, but the default error message "Something went wrong." is too generic.
Consider these improvements:
- Add an abstract method for generating error messages:
export abstract class ContextualError<
$Name extends string = string,
$Context extends object = object,
$Cause extends Error | undefined = Error | undefined,
> extends Error {
public name: $Name;
public context: $Context;
public cause: $Cause;
+ protected abstract formatMessage(): string;
constructor(
...args: undefined extends $Cause
? [context: $Context, cause?: $Cause]
: [context: $Context, cause: $Cause]
) {
const [context, cause] = args;
- super('Something went wrong.', { cause });
+ super('', { cause });
this.name = this.constructor.name as $Name;
this.context = context;
this.cause = cause as $Cause;
+ this.message = this.formatMessage();
}
}
📝 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 abstract class ContextualError< | |
$Name extends string = string, | |
$Context extends object = object, | |
$Cause extends Error | undefined = Error | undefined, | |
> extends Error { | |
public name: $Name; | |
public context: $Context; | |
public cause: $Cause; | |
constructor( | |
...args: undefined extends $Cause | |
? [context: $Context, cause?: $Cause] | |
: [context: $Context, cause: $Cause] | |
) { | |
const [context, cause] = args; | |
super('Something went wrong.', { cause }); | |
this.name = this.constructor.name as $Name; | |
this.context = context; | |
this.cause = cause as $Cause; | |
} | |
} | |
export abstract class ContextualError< | |
$Name extends string = string, | |
$Context extends object = object, | |
$Cause extends Error | undefined = Error | undefined, | |
> extends Error { | |
public name: $Name; | |
public context: $Context; | |
public cause: $Cause; | |
+ protected abstract formatMessage(): string; | |
constructor( | |
...args: undefined extends $Cause | |
? [context: $Context, cause?: $Cause] | |
: [context: $Context, cause: $Cause] | |
) { | |
const [context, cause] = args; | |
- super('Something went wrong.', { cause }); | |
+ super('', { cause }); | |
this.name = this.constructor.name as $Name; | |
this.context = context; | |
this.cause = cause as $Cause; | |
+ this.message = this.formatMessage(); | |
} | |
} |
I don't know how to test Sentry yet in our test suites, will explore that next. |
🐋 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/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/urvflunntxo5ox3ydgnp46dui",
"containerimage.config.digest": "sha256:709e7062ae150b8a860024e56999e950dc519df21d90ca536f48e8715b72b4a4",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:63859d7e5163cdbb769e316007a8fc665ba9497e1dae2bb32d28f4a0ca3148da",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:63859d7e5163cdbb769e316007a8fc665ba9497e1dae2bb32d28f4a0ca3148da",
"image.name": "ghcr.io/graphql-hive/app:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/app:console_1077-arm64"
},
"buildx.build.warnings": [
{
"vertex": "sha256:43407945f5e31b89d334978cce8ebedc59ef8551e26be9f6177fcb7f18a726b4",
"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:da6edd493d9fd5969f999dd48264ee4a33fb19df10eb78ab43b20b6ededfbb23",
"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:da6edd493d9fd5969f999dd48264ee4a33fb19df10eb78ab43b20b6ededfbb23",
"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:da6edd493d9fd5969f999dd48264ee4a33fb19df10eb78ab43b20b6ededfbb23",
"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:43407945f5e31b89d334978cce8ebedc59ef8551e26be9f6177fcb7f18a726b4",
"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:da6edd493d9fd5969f999dd48264ee4a33fb19df10eb78ab43b20b6ededfbb23",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAxMik=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 12
},
"end": {
"line": 12
}
}
]
},
{
"vertex": "sha256:da6edd493d9fd5969f999dd48264ee4a33fb19df10eb78ab43b20b6ededfbb23",
"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:da6edd493d9fd5969f999dd48264ee4a33fb19df10eb78ab43b20b6ededfbb23",
"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:43407945f5e31b89d334978cce8ebedc59ef8551e26be9f6177fcb7f18a726b4",
"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:43407945f5e31b89d334978cce8ebedc59ef8551e26be9f6177fcb7f18a726b4",
"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:43407945f5e31b89d334978cce8ebedc59ef8551e26be9f6177fcb7f18a726b4",
"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:43407945f5e31b89d334978cce8ebedc59ef8551e26be9f6177fcb7f18a726b4",
"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:43407945f5e31b89d334978cce8ebedc59ef8551e26be9f6177fcb7f18a726b4",
"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:43407945f5e31b89d334978cce8ebedc59ef8551e26be9f6177fcb7f18a726b4",
"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
}
}
]
}
],
"composition-federation-2": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/tqzc5p3vc68kycky04oerea2r",
"containerimage.config.digest": "sha256:d17816b570974ace2f6b6d7f08cd8ac0adacfaa2ae23e58a4c7ea3defb18a6ab",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:14f6eedef335a694231cf0cf1e9b1ac96c39be461bfe8998d86bd1bedbdd9f8d",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:14f6eedef335a694231cf0cf1e9b1ac96c39be461bfe8998d86bd1bedbdd9f8d",
"image.name": "ghcr.io/graphql-hive/composition-federation-2:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/composition-federation-2:console_1077-arm64"
},
"emails": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/oghygyzktg9tgtxcn8kres0q9",
"containerimage.config.digest": "sha256:188764e09887203324b4b1d6a6662a9f707d3de5bd7ee7ea4186d0af895daaee",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:18b6c33ba844dfcb5d39f1038dce5f1e240d980dd61ba526bd7ab1f1ccca35bf",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:18b6c33ba844dfcb5d39f1038dce5f1e240d980dd61ba526bd7ab1f1ccca35bf",
"image.name": "ghcr.io/graphql-hive/emails:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/emails:console_1077-arm64"
},
"policy": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/ffcc7msg5sql5swqnbvev2tgi",
"containerimage.config.digest": "sha256:35e5027fcacc5d23d71d0e9e43b8a8bbbd33cc8998a96ea5f5bbb05e66d5ad48",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:b542aafb1f06569be983ced844e47b6cb5607db70d8d0c85bc1a166bc87f507e",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:b542aafb1f06569be983ced844e47b6cb5607db70d8d0c85bc1a166bc87f507e",
"image.name": "ghcr.io/graphql-hive/policy:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/policy:console_1077-arm64"
},
"rate-limit": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/oku71gb61eolnrd6srnvmm7c9",
"containerimage.config.digest": "sha256:9b4377b0b8d467f57209522a9053544406f2f78fe333ea00f969bf673ab01e55",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:784bdb8cd889ce01a5fead4bff4984efbd5b83715845dfba7a80b21918b3bc12",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:784bdb8cd889ce01a5fead4bff4984efbd5b83715845dfba7a80b21918b3bc12",
"image.name": "ghcr.io/graphql-hive/rate-limit:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/rate-limit:console_1077-arm64"
},
"schema": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/7euezomxas0bn0mdc63mgneni",
"containerimage.config.digest": "sha256:ee241083fd6dfc4df69308e47e580e65d9d8bc91ce6fe5d48c797d656facd864",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:98428e5dc86b6fd31d1d809f2e2d9c3013e40821057c65819cac424a75f18d02",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:98428e5dc86b6fd31d1d809f2e2d9c3013e40821057c65819cac424a75f18d02",
"image.name": "ghcr.io/graphql-hive/schema:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/schema:console_1077-arm64"
},
"server": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/d74vvdwn6gp6i2i60zkusiebj",
"containerimage.config.digest": "sha256:05fcf89242d3e6101a3b0491afbe315e5e05099103fcacc502f8d399662ccb49",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:154f598156cf04cfd9c1557b146b707c18c14d185854ba15467f51e43a94c80d",
"size": 2076,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:154f598156cf04cfd9c1557b146b707c18c14d185854ba15467f51e43a94c80d",
"image.name": "ghcr.io/graphql-hive/server:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/server:console_1077-arm64"
},
"storage": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/i8lvhz0wqldccxo6j74013tin",
"containerimage.config.digest": "sha256:b409f678af3b59e02df4bd0088a03bc4405c5517a0a9af22abaf3f09962d5be0",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:0349fb25e881fd0c9f6ae4385ff4adc1ceeb186bc8ee2292230e0f0f7e932b89",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:0349fb25e881fd0c9f6ae4385ff4adc1ceeb186bc8ee2292230e0f0f7e932b89",
"image.name": "ghcr.io/graphql-hive/storage:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/storage:console_1077-arm64"
},
"stripe-billing": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/to1ote90ptpygdph73uekmvq9",
"containerimage.config.digest": "sha256:fabb21ecd80a17bf9b1972c19ea11323d5b6020e08776504aa39e3420383f83f",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:2c02af305b3502e0ce0318dfda97912ef872839145b09b5888d24155ee0446c6",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:2c02af305b3502e0ce0318dfda97912ef872839145b09b5888d24155ee0446c6",
"image.name": "ghcr.io/graphql-hive/stripe-billing:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/stripe-billing:console_1077-arm64"
},
"tokens": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/i1k2tzm9umd496ad4who2zuv1",
"containerimage.config.digest": "sha256:ee306fbd54f52b64820d0a64af636e594510ed3800db21ba92b28dcc80b92e82",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:1f87d28976fc4e9b62d02385d2c177d79d2e37cd6a29e57f1ad18096149ad10d",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:1f87d28976fc4e9b62d02385d2c177d79d2e37cd6a29e57f1ad18096149ad10d",
"image.name": "ghcr.io/graphql-hive/tokens:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/tokens:console_1077-arm64"
},
"usage": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/kv9lhar2khtziyddealpzv1u8",
"containerimage.config.digest": "sha256:67d799efa633632cf9cec12452d9c53b635ebc27174f5e042fab229883686f20",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:5cf4021ab4f1bfb1c206ace4e8cdd50071343b30a999f52e76d3eab66e900d05",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:5cf4021ab4f1bfb1c206ace4e8cdd50071343b30a999f52e76d3eab66e900d05",
"image.name": "ghcr.io/graphql-hive/usage:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/usage:console_1077-arm64"
},
"usage-estimator": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/qjsfc4y126cs3nv4833ohrdn9",
"containerimage.config.digest": "sha256:4e0b5c6f1abd5e08e506ccf7925114d1255dd3293d9bbffb380bc8e29eb289e3",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:33a0ed04f4e4bd76059c4d2093dedbfcaa3771d9f57116dcd8468fe956c56c3b",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:33a0ed04f4e4bd76059c4d2093dedbfcaa3771d9f57116dcd8468fe956c56c3b",
"image.name": "ghcr.io/graphql-hive/usage-estimator:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/usage-estimator:console_1077-arm64"
},
"usage-ingestor": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/4ikkr3e489j41tt0qoanbgdun",
"containerimage.config.digest": "sha256:8fc7362b60bc5c31690639fd7e8029bbeb511d4eab65a9c3c1538e160c702caa",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:e87c9b9f9b579151735df27a871032969307db09475dd1023d6c1ba01c2eeed4",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:e87c9b9f9b579151735df27a871032969307db09475dd1023d6c1ba01c2eeed4",
"image.name": "ghcr.io/graphql-hive/usage-ingestor:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/usage-ingestor:console_1077-arm64"
},
"webhooks": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?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": "45759d68bcd46566b1c5c1fae5fdcbee805c4f90",
"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": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:dockerfile": "nf5ka4e3ldtpo0zup2awjjgh0",
"local-sessionid:shared": "nf5ka4e3ldtpo0zup2awjjgh0"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-ad1f7f5d-ac47-4c57-8963-4f4b35c00438/builder-ad1f7f5d-ac47-4c57-8963-4f4b35c004380/vq9zv4zw3axgc8zwdv9xf00x6",
"containerimage.config.digest": "sha256:4004f1e9e9a8705cc63dadef97e87880888baed5319a5c069b2a8873367d9244",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:b8c9b80262bfba5378b655993b33fa67b488ce44c11fd8b4cac0ba40a9d78e97",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:b8c9b80262bfba5378b655993b33fa67b488ce44c11fd8b4cac0ba40a9d78e97",
"image.name": "ghcr.io/graphql-hive/webhooks:45759d68bcd46566b1c5c1fae5fdcbee805c4f90-arm64,ghcr.io/graphql-hive/webhooks:console_1077-arm64"
}
} |
return result.data as any; // z.infer<Exclude<schema, undefined>>; | ||
} | ||
|
||
return json as any; // Kit.Json.Value; |
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.
nit: prefer unknown
to force us to use validation or 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.
Since this is in the return position of an implementation it would not work and it does not matter, TS just doesn't make it possible to make implementations type safe. At best we could cast it to something matching the return type but its more maintenance for little gain and no increased type safety since it is a cast either way.
}, | ||
$Cause extends z.ZodError | SyntaxError | TypeError | DOMException, | ||
> extends Kit.Errors.ContextualError<$Name, $Context, $Cause> { | ||
message = 'Invalid response.'; |
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.
Prefer if we can provide more insight than this. E.g. should we include the cause's error message?
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.
It's all available through the chain data in a structured way. The missing part IMO is error renderers that are up to date with modern error types. Cause is part of the ECMA standard so it's confusing to me that default renderings are still AFAIK failing to raise good context about them. We would just have to add our own where it is needed such as top level catch all or logging middleware, etc.
super('Something went wrong.', { cause }); | ||
this.name = this.constructor.name as $Name; | ||
this.context = context; | ||
this.cause = cause as $Cause; |
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.
should the call to super
set this?
@@ -8,3 +8,20 @@ export const tryOr = <$PrimaryResult, $FallbackResult>( | |||
return fallback(); | |||
} | |||
}; | |||
|
|||
export const oneOf = <type extends readonly unknown[]>( |
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.
nit: Please add a description block to make the behavior more obvious when we use this function.
When seeing it used, I wasnt 100% sure it threw, or what type of error it would throw.
return value; | ||
} | ||
} | ||
throw new Error(`Unexpected value received by oneOf: ${value}`); |
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.
should this be a unique error class?
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.
Maybe! Its failure represents a defect not a normal error so we could encode that in a special class for sure.
import { fetchJson } from './fetch-json'; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-namespace | ||
export namespace SlackAPI { |
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.
personally im not a fan of namespaces in typescript. I think namespacing by import path is good enough and this just adds an extra layer of complexity.
If typescript had a global namespace like ruby, then namespaces would serve a more important role of course.
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.
I prefer using ESM but I received pushback using that approach on this repo. If the desired style of this repo is ultimately to use types and functions with stringly namespaced identifiers (e.g. slackAPIauthorize(...)
instead of `SlackAPI.authorize(...)) then I wasn't aware of that, and I think the DX on that is worse. I usually trade producer complexity for consumer simplicity based on my feeling that complexity should go down, not up, the stack.
// eslint-disable-next-line @typescript-eslint/no-namespace | ||
namespace SlackIntegrationErrors { | ||
export class DisabledError extends Kit.Errors.ContextualError<'DisabledError'> { | ||
message = 'The Slack integration is not enabled.'; |
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.
Are there any recommendations you could provide in this message for how to correct this if it needs correcting?
e.g. "set environment variable X" or "see "
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.
Worth putting a TODO about that here to keep the discussion going. We could write a catch all documentation here or link to some docs. Since this case is classified, however, upstream error rendering has the potential to switch on this and provide recommendations where it by definition has more context.
Error rendering is a really important thing that isn't addressed in this PR. For example that is where localization would be factored in, I think. Keeping strings out of error classes is generally good. But as you've pointed out in a few places, without good rendering, all that context and structure is just potential energy, not realized.
if (env.slack === null) { | ||
throw new Error('The Slack integration is not enabled.'); | ||
const error = new SlackIntegrationErrors.DisabledError({}); | ||
Sentry.captureException(error, { tags: sentryTagsRouteLevel }); |
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.
Do we have a request ID or any other identifiers that we could use to identify why/for who this is failing?
@jdolle thanks for the feedback. Feel free to take over this PR if you're interested! I'm currently on other tasks now without any plan to return here currently. If you see value here that's great, hope it helps! 🙏 |
Background
https://linear.app/the-guild/issue/CONSOLE-1077/sentry-alert-on-failure
Description
Solution has two parts.
Part 1, generic helpers:
Part 2, Slack Integration component:
Things I left out of this PR:
Those ideas would maximize captured context of errors sent to sentry events and pino. But I felt it would go too far in this PR to do that.
Checklist