From 6bde64103f9d3dfb4661ef6e0f42b7b6808f4191 Mon Sep 17 00:00:00 2001 From: Pedro <37028775+pedro-gomes-92@users.noreply.github.com> Date: Mon, 10 Feb 2025 16:27:34 +0800 Subject: [PATCH] feat: support access parameter for each project configuration --- ...-access-restrictions_2025-02-10-07-04.json | 10 ++++ common/reviews/api/rush-lib.api.md | 3 ++ .../rush-lib/src/api/RushConfiguration.ts | 5 +- .../src/api/RushConfigurationProject.ts | 47 ++++++++++++++++++- .../rush-lib/src/schemas/rush.schema.json | 6 +++ 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 common/changes/@microsoft/rush/pedrogomes-support-access-restrictions_2025-02-10-07-04.json diff --git a/common/changes/@microsoft/rush/pedrogomes-support-access-restrictions_2025-02-10-07-04.json b/common/changes/@microsoft/rush/pedrogomes-support-access-restrictions_2025-02-10-07-04.json new file mode 100644 index 00000000000..97e9da1d57f --- /dev/null +++ b/common/changes/@microsoft/rush/pedrogomes-support-access-restrictions_2025-02-10-07-04.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "provides access parameter to restrict packages to be installed", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index 26883d6c46c..a42f84e43af 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -1304,6 +1304,8 @@ export class RushConfigurationProject { // // @internal constructor(options: IRushConfigurationProjectOptions); + // Warning: (ae-forgotten-export) The symbol "PackageAccessType" needs to be exported by the entry point index.d.ts + readonly access: PackageAccessType; // @beta readonly configuredSubspaceName: string | undefined; get consumingProjects(): ReadonlySet; @@ -1335,6 +1337,7 @@ export class RushConfigurationProject { readonly tags: ReadonlySet; readonly tempProjectName: string; readonly unscopedTempProjectName: string; + validateAccess(): void; // @beta get versionPolicy(): VersionPolicy | undefined; // @beta diff --git a/libraries/rush-lib/src/api/RushConfiguration.ts b/libraries/rush-lib/src/api/RushConfiguration.ts index feac52b0c18..73c5d7f95a8 100644 --- a/libraries/rush-lib/src/api/RushConfiguration.ts +++ b/libraries/rush-lib/src/api/RushConfiguration.ts @@ -960,8 +960,11 @@ export class RushConfiguration { allowedProjectTags, subspace }); - subspace._addProject(project); + // Validates project according to its access restrictions + project.validateAccess(); + + subspace._addProject(project); this._projects.push(project); if (this._projectsByName.has(project.packageName)) { throw new Error( diff --git a/libraries/rush-lib/src/api/RushConfigurationProject.ts b/libraries/rush-lib/src/api/RushConfigurationProject.ts index 21e7062807a..a2114cb7311 100644 --- a/libraries/rush-lib/src/api/RushConfigurationProject.ts +++ b/libraries/rush-lib/src/api/RushConfigurationProject.ts @@ -29,6 +29,16 @@ export interface IRushConfigurationProjectJson { publishFolder?: string; tags?: string[]; subspaceName?: string; + access?: PackageAccessType; +} + +/** + * The type of package access restrictions + */ +export enum PackageAccessType { + Private = 'private', + Protected = 'protected', + Public = 'public' } /** @@ -206,13 +216,23 @@ export class RushConfigurationProject { */ public readonly configuredSubspaceName: string | undefined; + /** + * Access restrictions + */ + public readonly access: PackageAccessType; + /** @internal */ public constructor(options: IRushConfigurationProjectOptions) { const { projectJson, rushConfiguration, tempProjectName, allowedProjectTags } = options; - const { packageName, projectFolder: projectRelativeFolder } = projectJson; + const { + packageName, + projectFolder: projectRelativeFolder, + access = PackageAccessType.Public + } = projectJson; this.rushConfiguration = rushConfiguration; this.packageName = packageName; this.projectRelativeFolder = projectRelativeFolder; + this.access = access; validateRelativePathField(projectRelativeFolder, 'projectFolder', rushConfiguration.rushJsonFile); @@ -514,6 +534,31 @@ export class RushConfigurationProject { } return isMain; } + + /** + * Validates if this project can access its local dependencies. + * + */ + public validateAccess(): void { + const invalidDeps: string[] = []; + for (const project of this.dependencyProjects) { + if (project.access === PackageAccessType.Public) { + continue; + } else if (project.access === PackageAccessType.Private) { + invalidDeps.push(project.packageName); + } else if (this.subspace.subspaceName !== project.subspace.subspaceName) { + invalidDeps.push(project.packageName); + } + } + + if (invalidDeps.length > 0) { + throw new Error( + `${this.packageName} doesn't have permissions to access ${invalidDeps.join( + ', ' + )}.\nPlease remove this dependency or update the ${RushConstants.rushJsonFilename} access rights.` + ); + } + } } export function validateRelativePathField(relativePath: string, field: string, file: string): void { diff --git a/libraries/rush-lib/src/schemas/rush.schema.json b/libraries/rush-lib/src/schemas/rush.schema.json index dce5fcaae37..cdcb8da29e0 100644 --- a/libraries/rush-lib/src/schemas/rush.schema.json +++ b/libraries/rush-lib/src/schemas/rush.schema.json @@ -315,6 +315,12 @@ "subspaceName": { "description": "(EXPERIMENTAL) An optional entry for specifying which subspace this project belongs to if the subspaces feature is enabled.", "type": "string" + }, + "access": { + "description": "Restricts the project to be accessed by others. There are three possible values:\n\n\"public\" - any package can install this project.\n\"protected\" - only packages from the same subspace can install this project.\n\"private\" - no packages can install this project.\n\nThe default value is \"public\".", + "enum": ["public", "private", "protected"], + "type": "string", + "default": "public" } }, "additionalProperties": false,