From 2a2055fc5229875084bb9a96aac31d91d30a11ed Mon Sep 17 00:00:00 2001 From: Bilal Mahmoud Date: Wed, 11 Dec 2024 15:32:24 +0100 Subject: [PATCH] feat: replace lockfile-lint --- .github/workflows/lint.yml | 13 ----- Cargo.lock | 2 +- package.json | 21 ++------ yarn.config.cjs | 107 ++++++++++++++++++++++++++++--------- 4 files changed, 85 insertions(+), 58 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 36498fa6da9..b7a3ac600a5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -228,19 +228,6 @@ jobs: exit 1 fi - - name: Run yarn lint:lockfile-lint - if: ${{ success() || failure() }} - run: | - if ! yarn lint:lockfile-lint; then - echo '' - echo '' - echo 'ℹ️ ℹ️ ℹ️' - echo 'Try resetting yarn.lock to its previous state and then run `yarn install`.' - echo 'If your `~/.npmrc` mentions a custom registry, you should remove this setting first.' - echo 'ℹ️ ℹ️ ℹ️' - exit 1 - fi - - name: Run yarn lint:license-in-workspaces if: ${{ success() || failure() }} env: diff --git a/Cargo.lock b/Cargo.lock index 81f6101e290..3c6c7bf349b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3008,7 +3008,7 @@ name = "hash-graph-types" version = "0.0.0" dependencies = [ "bytes", - "derive_more 1.0.0", + "derive_more", "error-stack", "futures", "hash-codec", diff --git a/package.json b/package.json index 49161343803..cddde0e9787 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "lint:constraints": "yarn constraints", "lint:eslint": "turbo --continue lint:eslint --", "lint:license-in-workspaces": "yarn workspace @local/repo-chores exe scripts/check-license-in-workspaces.ts", - "lint:lockfile-lint": "lockfile-lint --path yarn.lock --type yarn --allowed-hosts npm yarn", "lint:markdownlint": "markdownlint --dot .", "lint:prettier": "prettier --check --ignore-unknown .", "lint:taplo": "taplo fmt --check", @@ -56,7 +55,7 @@ "postinstall": "turbo run postinstall", "seed-data:opensearch": "yarn workspace @apps/hash-search-loader clear-opensearch", "seed-data:redis": "yarn workspace @apps/hash-realtime clear-redis", - "seed-data": "concurrently \"yarn:seed-data:*\"", + "seed-data": "npm-run-all --parallel \"seed-data:*\"", "test": "npm-run-all --continue-on-error \"test:*\"", "test:unit": "turbo run test:unit --env-mode=loose --", "test:integration": "turbo run test:integration --env-mode=loose --", @@ -68,19 +67,9 @@ }, "prettier": { "plugins": [ - "prettier-plugin-packagejson", - "prettier-plugin-sh" + "prettier-plugin-packagejson" ], - "trailingComma": "all", - "overrides": [ - { - "files": "*.sql", - "options": { - "keywordCase": "upper", - "language": "postgresql" - } - } - ] + "trailingComma": "all" }, "resolutions": { "@artilleryio/int-commons@npm:2.11.0": "patch:@artilleryio/int-commons@npm%3A2.11.0#~/.yarn/patches/@artilleryio-int-commons-npm-2.11.0-5b69c05121.patch", @@ -116,15 +105,11 @@ "@sentry/cli": "^2.39.1", "@taplo/cli": "0.7.0", "@yarnpkg/types": "^4.0.0", - "concurrently": "7.6.0", "lefthook": "1.9.1", - "lockfile-lint": "4.14.0", "markdownlint-cli": "0.43.0", "npm-run-all2": "7.0.1", "prettier": "3.4.2", "prettier-plugin-packagejson": "2.5.6", - "prettier-plugin-sh": "0.14.0", - "suppress-exit-code": "3.2.0", "turbo": "2.3.3" }, "packageManager": "yarn@4.5.3+sha512.3003a14012e2987072d244c720506549c1aab73ee728208f1b2580a9fd67b92d61ba6b08fe93f6dce68fd771e3af1e59a0afa28dd242dd0940d73b95fedd4e90" diff --git a/yarn.config.cjs b/yarn.config.cjs index 0f921e4553c..513ecbec26f 100644 --- a/yarn.config.cjs +++ b/yarn.config.cjs @@ -22,6 +22,8 @@ const ignoredWorkspaces = [ "@blocks/person", ]; +const allowedGitDependencies = []; + /** * * @param {Dependency} dependency @@ -72,40 +74,94 @@ function enforceNoDualTypeDependencies({ Yarn }) { } /** - * Enforces the use of the `workspace:` protocol for all workspace dependencies. - * - * This rule ensures that all dependencies that are part of the workspace are - * declared using the `workspace:` protocol. + * Enforce that the package protocols are correct. * - * @param {Context} context - The Yarn constraint context. + * @param {Context} context */ -function enforceWorkspaceDependenciesDeclaredAsSuch({ Yarn }) { +function enforceProtocols({ Yarn }) { const workspaces = Yarn.workspaces(); for (const dependency of Yarn.dependencies()) { - if ( - workspaces.some( - (workspace) => - workspace.ident === dependency.ident && - workspace.pkg.version === dependency.range, - ) - ) { - dependency.update("workspace:^"); + if (shouldIgnoreDependency(dependency)) { + continue; + } + + const workspaceDependency = workspaces.find( + (workspace) => workspace.ident === dependency.ident, + ); + + if (workspaceDependency) { + // turbo doesn't support the `workspace:` protocol when rewriting lockfiles, leading to inconsistent lockfiles + dependency.update(workspaceDependency.pkg.version); } - } -} -/** - * This rule prohibits the use of the 'file:' protocol in dependency ranges - * and replaces it with the 'portal:' protocol. - * - * @param {Context} context - The Yarn constraint context. - */ -function enforcePortalProtocolInsteadOfFileProtocol({ Yarn }) { - for (const dependency of Yarn.dependencies()) { if (dependency.range.startsWith("file:")) { + // the file: protocol makes problems when used in conjunction with pnpm mode, portal is the equivalent protocol dependency.update(dependency.range.replace("file:", "portal:")); } + + if (dependency.range.startsWith("link:")) { + dependency.error( + `The link protocol allows for non-packages to be linked and is not allowed, dependency: ${dependency.ident}`, + ); + } + + if (dependency.range.startsWith("exec:")) { + dependency.error( + `The exec protocol allows for arbitrary code execution and is not allowed, dependency: ${dependency.ident}`, + ); + } + + let shouldCheckIfValidGitDependency = false; + + if ( + dependency.range.startsWith("https://") || + dependency.range.startsWith("http://") + ) { + // always prefix with the git protocol + dependency.update(`git:${dependency.range}`); + shouldCheckIfValidGitDependency = true; + } + + if (dependency.range.startsWith("ssh://")) { + // always prefix with the git protocol + dependency.update(`git:${dependency.range.replace(/^ssh:\/\//, "git:")}`); + shouldCheckIfValidGitDependency = true; + } + + if ( + (shouldCheckIfValidGitDependency || + dependency.range.startsWith("git:")) && + !allowedGitDependencies.includes(dependency.ident) + ) { + dependency.error( + `arbitrary git dependencies are not allowed, dependency: ${dependency.ident}`, + ); + } + + // patches are only allowed if they are for an `npm:` dpeendenct + if (dependency.range.startsWith("patch:")) { + const dependencySpecification = dependency.range.match(/^patch:([^#]+)/); + if (!dependencySpecification) { + dependency.error( + `invalid patch protocol, dependency: ${dependency.ident}`, + ); + continue; + } + + // locator is on the right side + // splitRight at `@` + const segments = dependencySpecification[1].split("@"); + const last = segments.pop(); + // urldecode the last segment + const version = decodeURIComponent(last); + + if (!version.startsWith("npm:")) { + dependency.error( + `patch protocol is only allowed for npm dependencies, dependency: ${dependency.ident}, patches: ${version}`, + ); + } + } } } @@ -180,10 +236,9 @@ function enforceDevDependenciesAreProperlyDeclared({ Yarn }) { module.exports = defineConfig({ async constraints(context) { - // enforceWorkspaceDependenciesDeclaredAsSuch(context); enforceConsistentDependenciesAcrossTheProject(context); enforceNoDualTypeDependencies(context); - // enforcePortalProtocolInsteadOfFileProtocol(context); + enforceProtocols(context); enforceDevDependenciesAreProperlyDeclared(context); }, });