diff --git a/.yarnrc.yml b/.yarnrc.yml index b9b25c0c5..0c65654ae 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -50,6 +50,11 @@ packageExtensions: querystring: "*" url: "*" util: "*" + "@types/npm-registry-fetch@^8.0.4": + dependencies: + "@types/node-fetch": "*" + "node-fetch": "*" + "@types/serve-static@*": dependencies: mime: "*" diff --git a/lunatrace/bsl/backend/package.json b/lunatrace/bsl/backend/package.json index 4961ac623..94ac7b456 100644 --- a/lunatrace/bsl/backend/package.json +++ b/lunatrace/bsl/backend/package.json @@ -26,7 +26,7 @@ "generate:hasura-calls": "graphql-codegen --config codegen.hasura.yml", "generate:custom-calls": "graphql-codegen --config codegen.lunatrace-custom.yml", "generate:github-calls": "graphql-codegen --config codegen.github.yml", - "generate": "yarn run generate:github-calls && yarn run generate:hasura-calls && yarn run generate:custom-calls", + "generate": "echo 'Parallel running:' && echo github\nhasura\ncustom | xargs -I% -n 1 -P 5 sh -c 'echo \" yarn run generate:%-calls\" & yarn run generate:%-calls'", "dev:graphql:watch": "yarn run generate:hasura-calls && watch 'yarn run generate:hasura-calls' ./src/hasura-api/graphql", "compile": "tsc -p tsconfig.json && cp src/graphql-yoga/schema.graphql build/graphql-yoga/schema.graphql", "compile:watch": "tsc -p tsconfig.json -w", @@ -52,6 +52,7 @@ "@jest/globals": "~28.1.3", "@lunatrace/logger": "workspace:~", "@lunatrace/lunatrace-common": "workspace:~", + "@lunatrace/npm-package-cli": "workspace:~", "@octokit/auth-app": "^3.6.1", "@octokit/graphql": "^4.8.0", "@octokit/plugin-rest-endpoint-methods": "^5.13.0", @@ -85,7 +86,6 @@ "markdown-table": "2.0.0", "minimatch": "~5.1.2", "murmurhash-native": "^3.5.0", - "node-fetch": "2", "nodemon": "^2.0.15", "octokit": "^1.7.1", "pg": "^8.7.1", diff --git a/lunatrace/bsl/backend/src/graphql-yoga/generated-resolver-types.ts b/lunatrace/bsl/backend/src/graphql-yoga/generated-resolver-types.ts index e0ba28093..1538e4674 100644 --- a/lunatrace/bsl/backend/src/graphql-yoga/generated-resolver-types.ts +++ b/lunatrace/bsl/backend/src/graphql-yoga/generated-resolver-types.ts @@ -141,6 +141,12 @@ export type BuildData_VulnerableRelease = { trivially_updatable: Scalars['String']; }; +export type CreatePullRequestForVulnerabilityResponse = { + __typename?: 'CreatePullRequestForVulnerabilityResponse'; + pullRequestUrl: Scalars['String']; + success?: Maybe; +}; + export type GithubRepository = { __typename?: 'GithubRepository'; cloneUrl: Scalars['String']; @@ -162,12 +168,22 @@ export type InstallSelectedReposResponse = { export type Mutation = { __typename?: 'Mutation'; + createPullRequestForVulnerability?: Maybe; installSelectedRepos?: Maybe; /** get s3 presigned url for manifest upload, used only by the frontend */ presignManifestUpload?: Maybe; }; +export type MutationCreatePullRequestForVulnerabilityArgs = { + new_package_slug: Scalars['String']; + old_package_slug: Scalars['String']; + package_manifest_path: Scalars['String']; + project_id: Scalars['uuid']; + vulnerability_id: Scalars['uuid']; +}; + + export type MutationInstallSelectedReposArgs = { orgs: Array; }; @@ -332,6 +348,7 @@ export type ResolversTypes = { BuildData_Vulnerability: ResolverTypeWrapper; BuildData_VulnerabilityCwe: ResolverTypeWrapper; BuildData_VulnerableRelease: ResolverTypeWrapper; + CreatePullRequestForVulnerabilityResponse: ResolverTypeWrapper; Float: ResolverTypeWrapper; GithubRepository: ResolverTypeWrapper; InstallSelectedReposResponse: ResolverTypeWrapper; @@ -367,6 +384,7 @@ export type ResolversParentTypes = { BuildData_Vulnerability: BuildData_Vulnerability; BuildData_VulnerabilityCwe: BuildData_VulnerabilityCwe; BuildData_VulnerableRelease: BuildData_VulnerableRelease; + CreatePullRequestForVulnerabilityResponse: CreatePullRequestForVulnerabilityResponse; Float: Scalars['Float']; GithubRepository: GithubRepository; InstallSelectedReposResponse: InstallSelectedReposResponse; @@ -508,6 +526,12 @@ export type BuildData_VulnerableReleaseResolvers; }; +export type CreatePullRequestForVulnerabilityResponseResolvers = { + pullRequestUrl?: Resolver; + success?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type GithubRepositoryResolvers = { cloneUrl?: Resolver; defaultBranch?: Resolver; @@ -528,6 +552,7 @@ export type InstallSelectedReposResponseResolvers = { + createPullRequestForVulnerability?: Resolver, ParentType, ContextType, RequireFields>; installSelectedRepos?: Resolver, ParentType, ContextType, RequireFields>; presignManifestUpload?: Resolver, ParentType, ContextType, RequireFields>; }; @@ -592,6 +617,7 @@ export type Resolvers = { BuildData_Vulnerability?: BuildData_VulnerabilityResolvers; BuildData_VulnerabilityCwe?: BuildData_VulnerabilityCweResolvers; BuildData_VulnerableRelease?: BuildData_VulnerableReleaseResolvers; + CreatePullRequestForVulnerabilityResponse?: CreatePullRequestForVulnerabilityResponseResolvers; GithubRepository?: GithubRepositoryResolvers; InstallSelectedReposResponse?: InstallSelectedReposResponseResolvers; Mutation?: MutationResolvers; diff --git a/lunatrace/bsl/backend/src/graphql-yoga/helpers/auth-helpers.ts b/lunatrace/bsl/backend/src/graphql-yoga/helpers/auth-helpers.ts index 815557870..83b424292 100644 --- a/lunatrace/bsl/backend/src/graphql-yoga/helpers/auth-helpers.ts +++ b/lunatrace/bsl/backend/src/graphql-yoga/helpers/auth-helpers.ts @@ -51,19 +51,16 @@ export function getUserId(ctx: Context, kratos_id_instead = false): string { return userId; } -export async function checkProjectIsAuthorized(projectId: string, ctx: Context): Promise { - const identityId = getUserId(ctx, true); - const usersAuthorizedProjects = await hasura.GetUsersProjects({ user_id: identityId }); - const userIsAuthorized = usersAuthorizedProjects.projects.some((p) => { - return p.id === projectId; - }); - if (!userIsAuthorized) { +export async function checkProjectIsAuthorizedOrThrow(projectId: string, ctx: Context): Promise { + const identityId = getUserId(ctx); + const project = await hasura.GetUserProjectFromProjectId({ project_id: projectId, user_id: identityId }); + if (project.projects.length === 0) { throw new GraphQLYogaError('Not authorized for this project'); } return; } -export async function checkBuildsAreAuthorized(buildIds: string[], ctx: Context): Promise { +export async function checkBuildsAreAuthorizedOrThrow(buildIds: string[], ctx: Context): Promise { const userId = getUserId(ctx); const existingBuildsRes = await hasura.GetUsersBuilds({ build_ids: buildIds, user_id: userId }); if (!existingBuildsRes.builds) { diff --git a/lunatrace/bsl/backend/src/graphql-yoga/resolvers/create-pull-request-for-vulnerability.ts b/lunatrace/bsl/backend/src/graphql-yoga/resolvers/create-pull-request-for-vulnerability.ts new file mode 100644 index 000000000..743589d98 --- /dev/null +++ b/lunatrace/bsl/backend/src/graphql-yoga/resolvers/create-pull-request-for-vulnerability.ts @@ -0,0 +1,142 @@ +/* + * Copyright by LunaSec (owned by Refinery Labs, Inc) + * + * Licensed under the Business Source License v1.1 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * https://github.com/lunasec-io/lunasec/blob/master/licenses/BSL-LunaTrace.txt + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { GraphQLYogaError } from '@graphql-yoga/node'; +import { + PullRequestOctokit, + replacePackageAndFileGitHubPullRequest, +} from '@lunatrace/npm-package-cli/src/package/github-pr'; + +import { getInstallationAccessToken } from '../../github/auth'; +import { hasura } from '../../hasura-api'; +import { log } from '../../utils/log'; +import { MutationResolvers } from '../generated-resolver-types'; +import { checkProjectIsAuthorizedOrThrow, isAuthenticated } from '../helpers/auth-helpers'; + +type CreatePullRequestForVulnerabilityType = NonNullable; + +function splitGitHubRepoPath(gitHubRepo: string) { + const split = gitHubRepo.split('/'); + const owner = split[split.length - 2]; + const repo = split[split.length - 1].replace('.git', ''); + return { owner, repo }; +} + +/** + * Installs the repos the user selected in the GUIG + */ +export const createPullRequestForVulnerabilityResolver: CreatePullRequestForVulnerabilityType = async ( + parent, + args, + ctx, + _info +) => { + try { + if (!isAuthenticated(ctx)) { + log.warn('No parsed JWT claims with a user ID on route that required authorization, throwing a graphql error'); + throw new GraphQLYogaError('Unauthorized'); + } + + const vulnerabilityId = args.vulnerability_id; + if (!vulnerabilityId) { + throw new GraphQLYogaError('No vulnerability id provided'); + } + + const projectId = args.project_id; + if (!projectId) { + throw new GraphQLYogaError('No project id provided'); + } + + const oldPackageSlug = args.old_package_slug; + if (!oldPackageSlug) { + throw new GraphQLYogaError('No old package slug provided'); + } + + const newPackageSlug = args.new_package_slug; + if (!newPackageSlug) { + throw new GraphQLYogaError('No new package slug provided'); + } + + const packageManifestPath = args.package_manifest_path; + if (!packageManifestPath) { + throw new GraphQLYogaError('No package manifest path provided'); + } + + // Strips out the actual package.json/yarn.lock/package-lock.json from the path since we just need the folder. + const normalizedPackageManifestPath = packageManifestPath + .replace(/package\.json$/, '') + .replace(/yarn\.lock$/, '') + .replace(/package-lock\.json$/, ''); + + await checkProjectIsAuthorizedOrThrow(projectId, ctx); + + const installationIdResult = await hasura.GetGitHubInstallationIdFromProjectId({ + project_id: projectId, + }); + + if (installationIdResult.projects.length === 0) { + throw new GraphQLYogaError('No project found when fetching installation id'); + } + + const installationId = installationIdResult.projects[0].organization?.installation_id; + + if (!installationId) { + throw new GraphQLYogaError('No installation id found for project'); + } + + const githubRepo = installationIdResult.projects[0].github_repository?.git_url; + + if (!githubRepo) { + throw new GraphQLYogaError('No github repo found for project'); + } + + const { owner, repo } = splitGitHubRepoPath(githubRepo); + + const installationAccessTokenRes = await getInstallationAccessToken(installationId); + if (installationAccessTokenRes.error) { + log.error('Failed to fetch installation access token', { installationAccessTokenRes }); + throw new Error('Error fetching installation access token'); + } + + const installationAccessToken = installationAccessTokenRes.res; + + const octokit = new PullRequestOctokit({ + auth: installationAccessToken, + }); + + const pullRequestResult = await replacePackageAndFileGitHubPullRequest( + octokit, + owner, + repo, + normalizedPackageManifestPath, + // TODO: Make this less hacky and brittle + packageManifestPath.endsWith('package-lock.json') ? 'npm' : 'yarn', + oldPackageSlug, + newPackageSlug + ); + + // TODO: Actually implement this endpoint instead of this stub + return { + success: true, + pullRequestUrl: pullRequestResult.pullRequestUrl, + }; + } catch (error) { + // TODO: temporary error handler until i figure out how to deal with global errors in yoga which seems maybe impossible + if (error instanceof GraphQLYogaError) { + log.warn('handled graphql yoga error, returning error to client', { error }); + } else { + log.error('UNKNOWN ERROR IN GRAPHQL RESOLVER', { e: error }); + } + throw error; + } +}; diff --git a/lunatrace/bsl/backend/src/graphql-yoga/resolvers/index.ts b/lunatrace/bsl/backend/src/graphql-yoga/resolvers/index.ts index 5e5ccf0c9..253508d12 100644 --- a/lunatrace/bsl/backend/src/graphql-yoga/resolvers/index.ts +++ b/lunatrace/bsl/backend/src/graphql-yoga/resolvers/index.ts @@ -17,6 +17,7 @@ import { Resolvers } from '../generated-resolver-types'; import { authenticatedRepoCloneUrlResolver } from './authenticated-repo-clone-url'; import { availableOrgsWithReposResolver } from './available-repos'; +import { createPullRequestForVulnerabilityResolver } from './create-pull-request-for-vulnerability'; import { installSelectedReposResolver } from './install-selected-repos'; import { presignManifestUploadResolver } from './presign-manifest-upload'; import { presignSbomUploadResolver } from './presign-sbom-upload'; @@ -34,6 +35,7 @@ export const resolvers: Resolvers = { Mutation: { presignManifestUpload: presignManifestUploadResolver, installSelectedRepos: installSelectedReposResolver, + createPullRequestForVulnerability: createPullRequestForVulnerabilityResolver, }, uuid: GraphQLUUID, jsonb: GraphQLJSON, diff --git a/lunatrace/bsl/backend/src/graphql-yoga/resolvers/presign-manifest-upload.ts b/lunatrace/bsl/backend/src/graphql-yoga/resolvers/presign-manifest-upload.ts index 1b22da455..207b8dd18 100644 --- a/lunatrace/bsl/backend/src/graphql-yoga/resolvers/presign-manifest-upload.ts +++ b/lunatrace/bsl/backend/src/graphql-yoga/resolvers/presign-manifest-upload.ts @@ -17,7 +17,7 @@ import { v4 as uuid } from 'uuid'; import { getBackendBucketConfig } from '../../config'; import { aws } from '../../utils/aws-utils'; import { MutationResolvers } from '../generated-resolver-types'; -import { checkProjectIsAuthorized, throwIfUnauthenticated } from '../helpers/auth-helpers'; +import { checkProjectIsAuthorizedOrThrow, throwIfUnauthenticated } from '../helpers/auth-helpers'; type PresignManifestUploadResolver = NonNullable; @@ -26,7 +26,7 @@ const sbomHandlerConfig = getBackendBucketConfig(); export const presignManifestUploadResolver: PresignManifestUploadResolver = async (parent, args, ctx, info) => { throwIfUnauthenticated(ctx); const projectId = args.project_id; - await checkProjectIsAuthorized(projectId, ctx); + await checkProjectIsAuthorizedOrThrow(projectId, ctx); const today = new Date(); const uniqueId = uuid(); diff --git a/lunatrace/bsl/backend/src/graphql-yoga/resolvers/sbom-url.ts b/lunatrace/bsl/backend/src/graphql-yoga/resolvers/sbom-url.ts index d63543427..cfe645fd9 100644 --- a/lunatrace/bsl/backend/src/graphql-yoga/resolvers/sbom-url.ts +++ b/lunatrace/bsl/backend/src/graphql-yoga/resolvers/sbom-url.ts @@ -18,14 +18,14 @@ import { hasura } from '../../hasura-api'; import { aws } from '../../utils/aws-utils'; import { log } from '../../utils/log'; import { QueryResolvers } from '../generated-resolver-types'; -import { checkProjectIsAuthorized, throwIfUnauthenticated } from '../helpers/auth-helpers'; +import { checkProjectIsAuthorizedOrThrow, throwIfUnauthenticated } from '../helpers/auth-helpers'; type sbomUrlResolverT = NonNullable; export const sbomUrlResolver: sbomUrlResolverT = async (parent, args, ctx, info) => { throwIfUnauthenticated(ctx); const build = await hasura.GetBuild({ build_id: args.buildId }); - await checkProjectIsAuthorized(build.builds_by_pk?.project?.id, ctx); + await checkProjectIsAuthorizedOrThrow(build.builds_by_pk?.project?.id, ctx); try { return formatUrl(await aws.signArbitraryS3URL(build.builds_by_pk?.s3_url || '', 'GET')); diff --git a/lunatrace/bsl/backend/src/graphql-yoga/resolvers/vulnerable-releases-from-build.ts b/lunatrace/bsl/backend/src/graphql-yoga/resolvers/vulnerable-releases-from-build.ts index 0a7e46058..d1f67f3bb 100644 --- a/lunatrace/bsl/backend/src/graphql-yoga/resolvers/vulnerable-releases-from-build.ts +++ b/lunatrace/bsl/backend/src/graphql-yoga/resolvers/vulnerable-releases-from-build.ts @@ -17,14 +17,14 @@ import { SeverityNamesOsv, severityOrderOsv } from '@lunatrace/lunatrace-common' import { loadTree } from '../../models/vulnerability-dependency-tree/load-tree'; import { log } from '../../utils/log'; import { QueryResolvers } from '../generated-resolver-types'; -import { checkBuildsAreAuthorized, throwIfUnauthenticated } from '../helpers/auth-helpers'; +import { checkBuildsAreAuthorizedOrThrow, throwIfUnauthenticated } from '../helpers/auth-helpers'; type BuildVulnerabilitiesResolver = NonNullable; export const vulnerableReleasesFromBuildResolver: BuildVulnerabilitiesResolver = async (parent, args, ctx, info) => { throwIfUnauthenticated(ctx); const buildId = args.buildId; - await checkBuildsAreAuthorized([buildId], ctx); + await checkBuildsAreAuthorizedOrThrow([buildId], ctx); const logger = log.child('vulnerable-releases-resolver', { buildId }); diff --git a/lunatrace/bsl/backend/src/graphql-yoga/schema.graphql b/lunatrace/bsl/backend/src/graphql-yoga/schema.graphql index e96c47004..80b613c21 100644 --- a/lunatrace/bsl/backend/src/graphql-yoga/schema.graphql +++ b/lunatrace/bsl/backend/src/graphql-yoga/schema.graphql @@ -26,6 +26,14 @@ type Mutation { installSelectedRepos( orgs: [OrgsWithReposInput!]! ): InstallSelectedReposResponse + createPullRequestForVulnerability( + project_id: uuid! + vulnerability_id: uuid! + """ We could pull this data from the database, probably, but it's easier to pass it in from the Frontend """ + old_package_slug: String! + new_package_slug: String! + package_manifest_path: String! + ): CreatePullRequestForVulnerabilityResponse } input OrgsWithReposInput { @@ -37,6 +45,11 @@ type InstallSelectedReposResponse { success: Boolean } +type CreatePullRequestForVulnerabilityResponse { + success: Boolean + pullRequestUrl: String! +} + input SbomUploadUrlInput { orgId: uuid! projectId: uuid! diff --git a/lunatrace/bsl/backend/src/hasura-api/generated.ts b/lunatrace/bsl/backend/src/hasura-api/generated.ts index c78014fe6..8f84a62a4 100644 --- a/lunatrace/bsl/backend/src/hasura-api/generated.ts +++ b/lunatrace/bsl/backend/src/hasura-api/generated.ts @@ -8521,10 +8521,6 @@ export type Query_Root = { vulnerability_affected_version_by_pk?: Maybe; /** fetch data from the table: "vulnerability.vulnerability" using primary key columns */ vulnerability_by_pk?: Maybe; - /** fetch data from the table: "vulnerability.cisa_known_exploited" */ - vulnerability_cisa_known_exploited: Array; - /** fetch data from the table: "vulnerability.cisa_known_exploited" using primary key columns */ - vulnerability_cisa_known_exploited_by_pk?: Maybe; /** fetch data from the table: "vulnerability.credit" */ vulnerability_credit: Array; /** fetch data from the table: "vulnerability.credit" using primary key columns */ @@ -9175,20 +9171,6 @@ export type Query_RootVulnerability_By_PkArgs = { }; -export type Query_RootVulnerability_Cisa_Known_ExploitedArgs = { - distinct_on?: InputMaybe>; - limit?: InputMaybe; - offset?: InputMaybe; - order_by?: InputMaybe>; - where?: InputMaybe; -}; - - -export type Query_RootVulnerability_Cisa_Known_Exploited_By_PkArgs = { - id: Scalars['uuid']; -}; - - export type Query_RootVulnerability_CreditArgs = { distinct_on?: InputMaybe>; limit?: InputMaybe; @@ -9987,10 +9969,6 @@ export type Subscription_Root = { vulnerability_affected_version_by_pk?: Maybe; /** fetch data from the table: "vulnerability.vulnerability" using primary key columns */ vulnerability_by_pk?: Maybe; - /** fetch data from the table: "vulnerability.cisa_known_exploited" */ - vulnerability_cisa_known_exploited: Array; - /** fetch data from the table: "vulnerability.cisa_known_exploited" using primary key columns */ - vulnerability_cisa_known_exploited_by_pk?: Maybe; /** fetch data from the table: "vulnerability.credit" */ vulnerability_credit: Array; /** fetch data from the table: "vulnerability.credit" using primary key columns */ @@ -10624,20 +10602,6 @@ export type Subscription_RootVulnerability_By_PkArgs = { }; -export type Subscription_RootVulnerability_Cisa_Known_ExploitedArgs = { - distinct_on?: InputMaybe>; - limit?: InputMaybe; - offset?: InputMaybe; - order_by?: InputMaybe>; - where?: InputMaybe; -}; - - -export type Subscription_RootVulnerability_Cisa_Known_Exploited_By_PkArgs = { - id: Scalars['uuid']; -}; - - export type Subscription_RootVulnerability_CreditArgs = { distinct_on?: InputMaybe>; limit?: InputMaybe; @@ -10929,8 +10893,6 @@ export type Vulnerability = { __typename?: 'vulnerability'; /** An array relationship */ affected: Array; - /** An object relationship */ - cisa_known_vuln?: Maybe; created_at: Scalars['timestamptz']; /** An array relationship */ credits: Array; @@ -11651,41 +11613,18 @@ export enum Vulnerability_Affected_Version_Update_Column { Version = 'version' } -/** order by aggregate values of table "vulnerability.vulnerability" */ -export type Vulnerability_Aggregate_Order_By = { - avg?: InputMaybe; - count?: InputMaybe; - max?: InputMaybe; - min?: InputMaybe; - stddev?: InputMaybe; - stddev_pop?: InputMaybe; - stddev_samp?: InputMaybe; - sum?: InputMaybe; - var_pop?: InputMaybe; - var_samp?: InputMaybe; - variance?: InputMaybe; -}; - /** append existing jsonb value of filtered columns with new jsonb value */ export type Vulnerability_Append_Input = { database_specific?: InputMaybe; upstream_data?: InputMaybe; }; -/** order by avg() on columns of table "vulnerability.vulnerability" */ -export type Vulnerability_Avg_Order_By = { - cvss_score?: InputMaybe; - epss_percentile?: InputMaybe; - epss_score?: InputMaybe; -}; - /** Boolean expression to filter rows from the table "vulnerability.vulnerability". All fields are combined with a logical 'AND'. */ export type Vulnerability_Bool_Exp = { _and?: InputMaybe>; _not?: InputMaybe; _or?: InputMaybe>; affected?: InputMaybe; - cisa_known_vuln?: InputMaybe; created_at?: InputMaybe; credits?: InputMaybe; cve_id?: InputMaybe; @@ -11714,90 +11653,6 @@ export type Vulnerability_Bool_Exp = { withdrawn?: InputMaybe; }; -/** columns and relationships of "vulnerability.cisa_known_exploited" */ -export type Vulnerability_Cisa_Known_Exploited = { - __typename?: 'vulnerability_cisa_known_exploited'; - cve?: Maybe; - date_added: Scalars['date']; - due_date: Scalars['date']; - id: Scalars['uuid']; - notes: Scalars['String']; - product: Scalars['String']; - required_action: Scalars['String']; - short_description: Scalars['String']; - vendor_project: Scalars['String']; - /** An array relationship */ - vulnerabilities: Array; - vulnerability_name: Scalars['String']; -}; - - -/** columns and relationships of "vulnerability.cisa_known_exploited" */ -export type Vulnerability_Cisa_Known_ExploitedVulnerabilitiesArgs = { - distinct_on?: InputMaybe>; - limit?: InputMaybe; - offset?: InputMaybe; - order_by?: InputMaybe>; - where?: InputMaybe; -}; - -/** Boolean expression to filter rows from the table "vulnerability.cisa_known_exploited". All fields are combined with a logical 'AND'. */ -export type Vulnerability_Cisa_Known_Exploited_Bool_Exp = { - _and?: InputMaybe>; - _not?: InputMaybe; - _or?: InputMaybe>; - cve?: InputMaybe; - date_added?: InputMaybe; - due_date?: InputMaybe; - id?: InputMaybe; - notes?: InputMaybe; - product?: InputMaybe; - required_action?: InputMaybe; - short_description?: InputMaybe; - vendor_project?: InputMaybe; - vulnerabilities?: InputMaybe; - vulnerability_name?: InputMaybe; -}; - -/** Ordering options when selecting data from "vulnerability.cisa_known_exploited". */ -export type Vulnerability_Cisa_Known_Exploited_Order_By = { - cve?: InputMaybe; - date_added?: InputMaybe; - due_date?: InputMaybe; - id?: InputMaybe; - notes?: InputMaybe; - product?: InputMaybe; - required_action?: InputMaybe; - short_description?: InputMaybe; - vendor_project?: InputMaybe; - vulnerabilities_aggregate?: InputMaybe; - vulnerability_name?: InputMaybe; -}; - -/** select columns of table "vulnerability.cisa_known_exploited" */ -export enum Vulnerability_Cisa_Known_Exploited_Select_Column { - /** column name */ - Cve = 'cve', - /** column name */ - DateAdded = 'date_added', - /** column name */ - DueDate = 'due_date', - /** column name */ - Id = 'id', - /** column name */ - Notes = 'notes', - /** column name */ - Product = 'product', - /** column name */ - RequiredAction = 'required_action', - /** column name */ - ShortDescription = 'short_description', - /** column name */ - VendorProject = 'vendor_project', - /** column name */ - VulnerabilityName = 'vulnerability_name' -} - /** unique or primary key constraints on table "vulnerability.vulnerability" */ export enum Vulnerability_Constraint { /** unique or primary key constraint on columns "id" */ @@ -12215,44 +12070,6 @@ export type Vulnerability_Insert_Input = { withdrawn?: InputMaybe; }; -/** order by max() on columns of table "vulnerability.vulnerability" */ -export type Vulnerability_Max_Order_By = { - created_at?: InputMaybe; - cve_id?: InputMaybe; - cvss_score?: InputMaybe; - details?: InputMaybe; - epss_percentile?: InputMaybe; - epss_score?: InputMaybe; - id?: InputMaybe; - last_fetched?: InputMaybe; - modified?: InputMaybe; - published?: InputMaybe; - severity_name?: InputMaybe; - source?: InputMaybe; - source_id?: InputMaybe; - summary?: InputMaybe; - withdrawn?: InputMaybe; -}; - -/** order by min() on columns of table "vulnerability.vulnerability" */ -export type Vulnerability_Min_Order_By = { - created_at?: InputMaybe; - cve_id?: InputMaybe; - cvss_score?: InputMaybe; - details?: InputMaybe; - epss_percentile?: InputMaybe; - epss_score?: InputMaybe; - id?: InputMaybe; - last_fetched?: InputMaybe; - modified?: InputMaybe; - published?: InputMaybe; - severity_name?: InputMaybe; - source?: InputMaybe; - source_id?: InputMaybe; - summary?: InputMaybe; - withdrawn?: InputMaybe; -}; - /** response of any mutation on the table "vulnerability.vulnerability" */ export type Vulnerability_Mutation_Response = { __typename?: 'vulnerability_mutation_response'; @@ -12279,7 +12096,6 @@ export type Vulnerability_On_Conflict = { /** Ordering options when selecting data from "vulnerability.vulnerability". */ export type Vulnerability_Order_By = { affected_aggregate?: InputMaybe; - cisa_known_vuln?: InputMaybe; created_at?: InputMaybe; credits_aggregate?: InputMaybe; cve_id?: InputMaybe; @@ -12788,34 +12604,6 @@ export enum Vulnerability_Severity_Update_Column { VulnerabilityId = 'vulnerability_id' } -/** order by stddev() on columns of table "vulnerability.vulnerability" */ -export type Vulnerability_Stddev_Order_By = { - cvss_score?: InputMaybe; - epss_percentile?: InputMaybe; - epss_score?: InputMaybe; -}; - -/** order by stddev_pop() on columns of table "vulnerability.vulnerability" */ -export type Vulnerability_Stddev_Pop_Order_By = { - cvss_score?: InputMaybe; - epss_percentile?: InputMaybe; - epss_score?: InputMaybe; -}; - -/** order by stddev_samp() on columns of table "vulnerability.vulnerability" */ -export type Vulnerability_Stddev_Samp_Order_By = { - cvss_score?: InputMaybe; - epss_percentile?: InputMaybe; - epss_score?: InputMaybe; -}; - -/** order by sum() on columns of table "vulnerability.vulnerability" */ -export type Vulnerability_Sum_Order_By = { - cvss_score?: InputMaybe; - epss_percentile?: InputMaybe; - epss_score?: InputMaybe; -}; - /** update columns of table "vulnerability.vulnerability" */ export enum Vulnerability_Update_Column { /** column name */ @@ -12856,27 +12644,6 @@ export enum Vulnerability_Update_Column { Withdrawn = 'withdrawn' } -/** order by var_pop() on columns of table "vulnerability.vulnerability" */ -export type Vulnerability_Var_Pop_Order_By = { - cvss_score?: InputMaybe; - epss_percentile?: InputMaybe; - epss_score?: InputMaybe; -}; - -/** order by var_samp() on columns of table "vulnerability.vulnerability" */ -export type Vulnerability_Var_Samp_Order_By = { - cvss_score?: InputMaybe; - epss_percentile?: InputMaybe; - epss_score?: InputMaybe; -}; - -/** order by variance() on columns of table "vulnerability.vulnerability" */ -export type Vulnerability_Variance_Order_By = { - cvss_score?: InputMaybe; - epss_percentile?: InputMaybe; - epss_score?: InputMaybe; -}; - /** CWEs that are defined for a vulnerability */ export type Vulnerability_Vulnerability_Cwe = { __typename?: 'vulnerability_vulnerability_cwe'; @@ -13210,6 +12977,13 @@ export type GetCountOfPersonalOrgQueryVariables = Exact<{ export type GetCountOfPersonalOrgQuery = { __typename?: 'query_root', organizations_aggregate: { __typename?: 'organizations_aggregate', aggregate?: { __typename?: 'organizations_aggregate_fields', count: number } | null } }; +export type GetGitHubInstallationIdFromProjectIdQueryVariables = Exact<{ + project_id: Scalars['uuid']; +}>; + + +export type GetGitHubInstallationIdFromProjectIdQuery = { __typename?: 'query_root', projects: Array<{ __typename?: 'projects', github_repository?: { __typename?: 'github_repositories', git_url: string, github_id?: number | null, github_node_id?: string | null } | null, organization?: { __typename?: 'organizations', installation_id?: number | null } | null }> }; + export type GetGithubRepositoriesByIdsQueryVariables = Exact<{ ids: Array | Scalars['Int']; }>; @@ -13283,6 +13057,14 @@ export type GetUserGitHubDataQueryVariables = Exact<{ export type GetUserGitHubDataQuery = { __typename?: 'query_root', users: Array<{ __typename?: 'users', github_id?: string | null, github_node_id?: string | null, kratos_id?: any | null, id: any }> }; +export type GetUserProjectFromProjectIdQueryVariables = Exact<{ + project_id: Scalars['uuid']; + user_id: Scalars['uuid']; +}>; + + +export type GetUserProjectFromProjectIdQuery = { __typename?: 'query_root', projects: Array<{ __typename?: 'projects', id: any }> }; + export type GetUserRoleQueryVariables = Exact<{ kratos_id?: InputMaybe; }>; @@ -13298,13 +13080,6 @@ export type GetUsersBuildsQueryVariables = Exact<{ export type GetUsersBuildsQuery = { __typename?: 'query_root', builds: Array<{ __typename?: 'builds', id: any }> }; -export type GetUsersProjectsQueryVariables = Exact<{ - user_id: Scalars['uuid']; -}>; - - -export type GetUsersProjectsQuery = { __typename?: 'query_root', projects: Array<{ __typename?: 'projects', id: any }> }; - export type GetVulnerabilitiesByCveQueryVariables = Exact<{ cves?: InputMaybe | Scalars['String']>; }>; @@ -13591,6 +13366,20 @@ export const GetCountOfPersonalOrgDocument = gql` } } `; +export const GetGitHubInstallationIdFromProjectIdDocument = gql` + query GetGitHubInstallationIdFromProjectId($project_id: uuid!) { + projects(where: {id: {_eq: $project_id}}, limit: 1) { + github_repository { + git_url + github_id + github_node_id + } + organization { + installation_id + } + } +} + `; export const GetGithubRepositoriesByIdsDocument = gql` query GetGithubRepositoriesByIds($ids: [Int!]!) { github_repositories(where: {github_id: {_in: $ids}}) { @@ -13769,6 +13558,16 @@ export const GetUserGitHubDataDocument = gql` } } `; +export const GetUserProjectFromProjectIdDocument = gql` + query GetUserProjectFromProjectId($project_id: uuid!, $user_id: uuid!) { + projects( + where: {organization: {organization_users: {user_id: {_eq: $user_id}}}, id: {_eq: $project_id}} + limit: 1 + ) { + id + } +} + `; export const GetUserRoleDocument = gql` query GetUserRole($kratos_id: uuid) { users(where: {kratos_id: {_eq: $kratos_id}}) { @@ -13786,15 +13585,6 @@ export const GetUsersBuildsDocument = gql` } } `; -export const GetUsersProjectsDocument = gql` - query GetUsersProjects($user_id: uuid!) { - projects( - where: {organization: {organization_users: {user: {kratos_id: {_eq: $user_id}}}}} - ) { - id - } -} - `; export const GetVulnerabilitiesByCveDocument = gql` query GetVulnerabilitiesByCve($cves: [String!]) { vulnerability(where: {source_id: {_in: $cves}}) { @@ -14082,6 +13872,9 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = GetCountOfPersonalOrg(variables: GetCountOfPersonalOrgQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(GetCountOfPersonalOrgDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'GetCountOfPersonalOrg', 'query'); }, + GetGitHubInstallationIdFromProjectId(variables: GetGitHubInstallationIdFromProjectIdQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { + return withWrapper((wrappedRequestHeaders) => client.request(GetGitHubInstallationIdFromProjectIdDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'GetGitHubInstallationIdFromProjectId', 'query'); + }, GetGithubRepositoriesByIds(variables: GetGithubRepositoriesByIdsQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(GetGithubRepositoriesByIdsDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'GetGithubRepositoriesByIds', 'query'); }, @@ -14112,15 +13905,15 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = GetUserGitHubData(variables?: GetUserGitHubDataQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(GetUserGitHubDataDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'GetUserGitHubData', 'query'); }, + GetUserProjectFromProjectId(variables: GetUserProjectFromProjectIdQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { + return withWrapper((wrappedRequestHeaders) => client.request(GetUserProjectFromProjectIdDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'GetUserProjectFromProjectId', 'query'); + }, GetUserRole(variables?: GetUserRoleQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(GetUserRoleDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'GetUserRole', 'query'); }, GetUsersBuilds(variables: GetUsersBuildsQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(GetUsersBuildsDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'GetUsersBuilds', 'query'); }, - GetUsersProjects(variables: GetUsersProjectsQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { - return withWrapper((wrappedRequestHeaders) => client.request(GetUsersProjectsDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'GetUsersProjects', 'query'); - }, GetVulnerabilitiesByCve(variables?: GetVulnerabilitiesByCveQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(GetVulnerabilitiesByCveDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'GetVulnerabilitiesByCve', 'query'); }, diff --git a/lunatrace/bsl/backend/src/hasura-api/graphql/get-github-installation-id-from-project-id.graphql b/lunatrace/bsl/backend/src/hasura-api/graphql/get-github-installation-id-from-project-id.graphql new file mode 100644 index 000000000..45be74dda --- /dev/null +++ b/lunatrace/bsl/backend/src/hasura-api/graphql/get-github-installation-id-from-project-id.graphql @@ -0,0 +1,12 @@ +query GetGitHubInstallationIdFromProjectId($project_id: uuid!) { + projects(where: {id: {_eq: $project_id}}, limit: 1) { + github_repository { + git_url + github_id + github_node_id + } + organization { + installation_id + } + } +} diff --git a/lunatrace/bsl/backend/src/hasura-api/graphql/get-user-project-from-project-id.graphql b/lunatrace/bsl/backend/src/hasura-api/graphql/get-user-project-from-project-id.graphql new file mode 100644 index 000000000..63b39959c --- /dev/null +++ b/lunatrace/bsl/backend/src/hasura-api/graphql/get-user-project-from-project-id.graphql @@ -0,0 +1,5 @@ +query GetUserProjectFromProjectId($project_id: uuid!, $user_id: uuid!) { + projects(where: {organization: {organization_users: {user_id: {_eq: $user_id}}}, id: {_eq: $project_id}}, limit: 1) { + id + } +} diff --git a/lunatrace/bsl/backend/src/hasura-api/graphql/get-users-projects.graphql b/lunatrace/bsl/backend/src/hasura-api/graphql/get-users-projects.graphql deleted file mode 100644 index 4c7e74918..000000000 --- a/lunatrace/bsl/backend/src/hasura-api/graphql/get-users-projects.graphql +++ /dev/null @@ -1,5 +0,0 @@ -query GetUsersProjects($user_id: uuid!) { - projects(where: {organization: {organization_users: {user: {kratos_id: {_eq: $user_id}}}}}) { - id - } -} diff --git a/lunatrace/npm-package-cli/package.json b/lunatrace/npm-package-cli/package.json index 9b33608d1..c3100d0ac 100644 --- a/lunatrace/npm-package-cli/package.json +++ b/lunatrace/npm-package-cli/package.json @@ -1,6 +1,6 @@ { - "name": "@lunasec/simple-npm-example", - "version": "0.0.0", + "name": "@lunatrace/npm-package-cli", + "version": "1.0.0", "description": "LunaTrace CLI for managing NPM package versions", "author": "@lunasec-io", "bin": { @@ -39,7 +39,6 @@ "@types/chai": "^4", "@types/jest": "^29.4.0", "@types/node": "^16.18.11", - "@types/node-fetch": "^2.6.2", "@types/npm-package-arg": "^6.1.1", "@types/npm-registry-fetch": "^8.0.4", "@types/npmcli__arborist": "^5.6.1", diff --git a/lunatrace/npm-package-cli/src/commands/github-pr/replace-package.ts b/lunatrace/npm-package-cli/src/commands/github-pr/replace-package.ts index a04e32ef6..c013028ca 100644 --- a/lunatrace/npm-package-cli/src/commands/github-pr/replace-package.ts +++ b/lunatrace/npm-package-cli/src/commands/github-pr/replace-package.ts @@ -16,11 +16,7 @@ */ import { Args, Command, Flags } from '@oclif/core'; -import { - PullRequestOctokit, - PullRequestOctokitType, - replacePackageAndFileGitHubPullRequest, -} from '../../package/github-pr'; +import { PullRequestOctokit, replacePackageAndFileGitHubPullRequest } from '../../package/github-pr'; import { PackageManagerType } from '../../package/types'; import { ReplacePackageFlags } from '../replace-package'; diff --git a/lunatrace/npm-package-cli/src/package/github-pr/index.ts b/lunatrace/npm-package-cli/src/package/github-pr/index.ts index 2298798db..5109fa55a 100644 --- a/lunatrace/npm-package-cli/src/package/github-pr/index.ts +++ b/lunatrace/npm-package-cli/src/package/github-pr/index.ts @@ -160,7 +160,7 @@ export async function replacePackageAndFileGitHubPullRequest( oldPackage: string, newPackage: string, ref?: string -): Promise { +): Promise<{ pullRequestUrl: string; pullRequestTitle: string }> { const repoAuthState = await getRepoAuthState(octokit, owner, repo); const checkoutRef = ref || repoAuthState.baseBranch; @@ -244,4 +244,9 @@ export async function replacePackageAndFileGitHubPullRequest( // Delete temporary directory await fs.promises.rm(tmpDirPath, { recursive: true, force: true }); + + return { + pullRequestUrl: pullRequest.data.html_url, + pullRequestTitle: pullRequest.data.title, + }; } diff --git a/lunatrace/npm-package-cli/src/tests/commands/show-tree/world.test.ts b/lunatrace/npm-package-cli/src/tests/commands/show-tree/world.test.ts deleted file mode 100644 index 0be85213d..000000000 --- a/lunatrace/npm-package-cli/src/tests/commands/show-tree/world.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2023 by LunaSec (owned by Refinery Labs, Inc) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -import { expect, test } from '@oclif/test'; - -describe('hello world', () => { - test - .stdout() - .command(['hello:world']) - .it('runs hello world cmd', (ctx) => { - expect(ctx.stdout).to.contain('hello world!'); - }); -}); diff --git a/lunatrace/npm-package-cli/tsconfig.json b/lunatrace/npm-package-cli/tsconfig.json index fe32d2c89..ce36b848f 100644 --- a/lunatrace/npm-package-cli/tsconfig.json +++ b/lunatrace/npm-package-cli/tsconfig.json @@ -8,8 +8,7 @@ "strict": true, "target": "es2019", "esModuleInterop": true, - "skipLibCheck": true, - "types": ["node", "jest", "@types/jest", "@types/node-fetch"] + "skipLibCheck": false }, "include": [ "src/**/*" diff --git a/yarn.lock b/yarn.lock index 0e3aac5b0..8a9a6c948 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13396,44 +13396,6 @@ __metadata: languageName: unknown linkType: soft -"@lunasec/simple-npm-example@workspace:lunatrace/npm-package-cli": - version: 0.0.0-use.local - resolution: "@lunasec/simple-npm-example@workspace:lunatrace/npm-package-cli" - dependencies: - "@npmcli/arborist": ^6.2.0 - "@oclif/core": ^2 - "@oclif/plugin-help": ^5 - "@oclif/plugin-plugins": ^2.2.4 - "@oclif/test": ^2.3.3 - "@octokit/core": ^4.2.0 - "@octokit/plugin-paginate-rest": ^6.0.0 - "@octokit/plugin-rest-endpoint-methods": ^7.0.1 - "@octokit/rest": ^19.0.7 - "@octokit/types": ^9.0.0 - "@types/chai": ^4 - "@types/jest": ^29.4.0 - "@types/node": ^16.18.11 - "@types/node-fetch": ^2.6.2 - "@types/npm-package-arg": ^6.1.1 - "@types/npm-registry-fetch": ^8.0.4 - "@types/npmcli__arborist": ^5.6.1 - "@types/pacote": ^11.1.5 - chai: ^4 - jest: ^29.4.1 - npm-package-arg: ^10.1.0 - oclif: ^3.6.1 - octokit-plugin-create-pull-request: ^4.1.1 - pacote: ^15.0.8 - shx: ^0.3.4 - ts-jest: ^29.0.5 - ts-node: ^10.4.0 - tslib: ^2.5.0 - typescript: ~4.7.0 - bin: - lunatrace-npm-cli: bin/run - languageName: unknown - linkType: soft - "@lunasec/tokenizer-sdk@^1.0.7, @lunasec/tokenizer-sdk@workspace:lunadefend/js/sdks/packages/tokenizer-sdk": version: 0.0.0-use.local resolution: "@lunasec/tokenizer-sdk@workspace:lunadefend/js/sdks/packages/tokenizer-sdk" @@ -13509,6 +13471,43 @@ __metadata: languageName: unknown linkType: soft +"@lunatrace/npm-package-cli@workspace:lunatrace/npm-package-cli, @lunatrace/npm-package-cli@workspace:~": + version: 0.0.0-use.local + resolution: "@lunatrace/npm-package-cli@workspace:lunatrace/npm-package-cli" + dependencies: + "@npmcli/arborist": ^6.2.0 + "@oclif/core": ^2 + "@oclif/plugin-help": ^5 + "@oclif/plugin-plugins": ^2.2.4 + "@oclif/test": ^2.3.3 + "@octokit/core": ^4.2.0 + "@octokit/plugin-paginate-rest": ^6.0.0 + "@octokit/plugin-rest-endpoint-methods": ^7.0.1 + "@octokit/rest": ^19.0.7 + "@octokit/types": ^9.0.0 + "@types/chai": ^4 + "@types/jest": ^29.4.0 + "@types/node": ^16.18.11 + "@types/npm-package-arg": ^6.1.1 + "@types/npm-registry-fetch": ^8.0.4 + "@types/npmcli__arborist": ^5.6.1 + "@types/pacote": ^11.1.5 + chai: ^4 + jest: ^29.4.1 + npm-package-arg: ^10.1.0 + oclif: ^3.6.1 + octokit-plugin-create-pull-request: ^4.1.1 + pacote: ^15.0.8 + shx: ^0.3.4 + ts-jest: ^29.0.5 + ts-node: ^10.4.0 + tslib: ^2.5.0 + typescript: ~4.7.0 + bin: + lunatrace-npm-cli: bin/run + languageName: unknown + linkType: soft + "@mdx-js/mdx@npm:1.6.22, @mdx-js/mdx@npm:^1.6.21": version: 1.6.22 resolution: "@mdx-js/mdx@npm:1.6.22" @@ -17609,16 +17608,6 @@ __metadata: languageName: node linkType: hard -"@types/node-fetch@npm:^2.6.2": - version: 2.6.2 - resolution: "@types/node-fetch@npm:2.6.2" - dependencies: - "@types/node": "*" - form-data: ^3.0.0 - checksum: 6f73b1470000d303d25a6fb92875ea837a216656cb7474f66cdd67bb014aa81a5a11e7ac9c21fe19bee9ecb2ef87c1962bceeaec31386119d1ac86e4c30ad7a6 - languageName: node - linkType: hard - "@types/node@npm:*, @types/node@npm:>= 8, @types/node@npm:^17.0.5": version: 17.0.21 resolution: "@types/node@npm:17.0.21" @@ -40363,6 +40352,7 @@ __metadata: "@jest/globals": ~28.1.3 "@lunatrace/logger": "workspace:~" "@lunatrace/lunatrace-common": "workspace:~" + "@lunatrace/npm-package-cli": "workspace:~" "@octokit/auth-app": ^3.6.1 "@octokit/graphql": ^4.8.0 "@octokit/openapi-types": ^11.2.0 @@ -40430,7 +40420,6 @@ __metadata: markdown-table: 2.0.0 minimatch: ~5.1.2 murmurhash-native: ^3.5.0 - node-fetch: 2 nodemon: ^2.0.15 octokit: ^1.7.1 pg: ^8.7.1 @@ -42837,20 +42826,6 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:2": - version: 2.6.8 - resolution: "node-fetch@npm:2.6.8" - dependencies: - whatwg-url: ^5.0.0 - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - checksum: 91f57be68e29f9b1382750693619e199733a6936998e6d618f1aa779853ad8fc4a2facf170db7957bf1d2510bad33449edf74b5802713d81b63de5986fa3be00 - languageName: node - linkType: hard - "node-fetch@npm:2.6.7, node-fetch@npm:^2.5.0, node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.7": version: 2.6.7 resolution: "node-fetch@npm:2.6.7"