From e6ac2a695878da792ab06793f4d3c2aa26d08831 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 20:21:00 +0000 Subject: [PATCH 1/7] build(deps): bump uuid in the npm_and_yarn group across 1 directory Bumps the npm_and_yarn group with 1 update in the / directory: [uuid](https://github.com/uuidjs/uuid). Updates `uuid` from 8.3.2 to 14.0.0 - [Release notes](https://github.com/uuidjs/uuid/releases) - [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md) - [Commits](https://github.com/uuidjs/uuid/compare/v8.3.2...v14.0.0) --- updated-dependencies: - dependency-name: uuid dependency-version: 14.0.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 24 ++++++++++++++---------- package.json | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index a5daebb9f..cdb557108 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "eslint-plugin-promise": "^6.6.0", "http-status-codes": "^2.2.0", "jest": "^29.5.0", - "jest-junit": "^16.0.0", + "jest-junit": "^17.0.0", "jest-when": "^3.5.2", "lockfile-lint": "^4.14.0", "nock": "^14.0.1", @@ -8873,19 +8873,19 @@ } }, "node_modules/jest-junit": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-16.0.0.tgz", - "integrity": "sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==", + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-17.0.0.tgz", + "integrity": "sha512-RYWCkq4j59gUXj5DsgbIE7xFBZzu1gtibPhyjSjMmGaOTLnqlXhg7x9zuGCwgbCuMAyoyvk0Mi8wSrRR5uOeLA==", "dev": true, "license": "Apache-2.0", "dependencies": { "mkdirp": "^1.0.4", "strip-ansi": "^6.0.1", - "uuid": "^8.3.2", + "uuid": "^14.0.0", "xml": "^1.0.1" }, "engines": { - "node": ">=10.12.0" + "node": ">=20.0.0" } }, "node_modules/jest-leak-detector": { @@ -13650,13 +13650,17 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist-node/bin/uuid" } }, "node_modules/v8-to-istanbul": { diff --git a/package.json b/package.json index 1bf4f13e7..302f9f205 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "eslint-plugin-promise": "^6.6.0", "http-status-codes": "^2.2.0", "jest": "^29.5.0", - "jest-junit": "^16.0.0", + "jest-junit": "^17.0.0", "jest-when": "^3.5.2", "lockfile-lint": "^4.14.0", "nock": "^14.0.1", From a680b0b2dae1a0243e72c79cf6dd3eda318ef31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Madis=20K=C3=B5osaar?= Date: Fri, 12 Jun 2026 20:04:41 +0300 Subject: [PATCH 2/7] Bug/archived repo (#991) * fix: apply org-level settings before loading repository configurations * fix: enhance descriptions and add new properties for security features in settings.json * fix: update description for deprecated squash-merge commit title property in settings.json * fix issue with archived repos --------- Co-authored-by: Yadhav Jayaraman <57544838+decyjphr@users.noreply.github.com> --- lib/settings.js | 7 ++- schema/dereferenced/settings.json | 21 +++++++ test/unit/lib/plugins/archive.test.js | 50 +++++++++++++++ test/unit/lib/settings.test.js | 87 +++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) diff --git a/lib/settings.js b/lib/settings.js index 919e01854..fd7ca2693 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -370,7 +370,7 @@ ${this.results.reduce((x, y) => { const RepoPlugin = Settings.PLUGINS.repository const archivePlugin = new Archive(this.nop, this.github, repo, repoConfig, this.log) - const { shouldArchive, shouldUnarchive } = await archivePlugin.getState() + const { isArchived, shouldArchive, shouldUnarchive } = await archivePlugin.getState() if (shouldUnarchive) { this.log.debug(`Unarchiving repo ${repo.repo}`) @@ -378,6 +378,11 @@ ${this.results.reduce((x, y) => { this.appendToResults(unArchiveResults) } + if (isArchived && !shouldUnarchive) { + this.log.debug(`Skipping repo/child plugin updates for archived repo ${repo.repo}`) + return + } + const repoResults = await new RepoPlugin(this.nop, this.github, repo, repoConfig, this.installation_id, this.log, this.errors).sync() this.appendToResults(repoResults) diff --git a/schema/dereferenced/settings.json b/schema/dereferenced/settings.json index 8698b2012..4dcdf0eb6 100644 --- a/schema/dereferenced/settings.json +++ b/schema/dereferenced/settings.json @@ -50,6 +50,17 @@ } } }, + "code_security": { + "type": "object", + "description": "Use the `status` property to enable or disable GitHub Code Security for this repository.", + "description": "Use the `status` property to enable or disable GitHub Advanced Security for this repository.\nFor more information, see \"[About GitHub Advanced\nSecurity](/github/getting-started-with-github/learning-about-github/about-github-advanced-security).\"\n\nFor standalone Code Scanning or Secret Protection products, this parameter cannot be used.", + "properties": { + "status": { + "type": "string", + "description": "Can be `enabled` or `disabled`." + } + } + }, "code_security": { "type": "object", "description": "Use the `status` property to enable or disable GitHub Code Security for this repository.", @@ -90,6 +101,16 @@ } } }, + "secret_scanning_ai_detection": { + "type": "object", + "description": "Use the `status` property to enable or disable secret scanning AI detection for this repository. For more information, see \"[Responsible detection of generic secrets with AI](https://docs.github.com/code-security/secret-scanning/using-advanced-secret-scanning-and-push-protection-features/generic-secret-detection/responsible-ai-generic-secrets).\"", + "properties": { + "status": { + "type": "string", + "description": "Can be `enabled` or `disabled`." + } + } + }, "secret_scanning_non_provider_patterns": { "type": "object", "description": "Use the `status` property to enable or disable secret scanning non-provider patterns for this repository. For more information, see \"[Supported secret scanning patterns](/code-security/secret-scanning/introduction/supported-secret-scanning-patterns#supported-secrets).\"", diff --git a/test/unit/lib/plugins/archive.test.js b/test/unit/lib/plugins/archive.test.js index 0ed0f38d1..a60eafac4 100644 --- a/test/unit/lib/plugins/archive.test.js +++ b/test/unit/lib/plugins/archive.test.js @@ -93,6 +93,56 @@ describe('Archive Plugin', () => { }) }) + describe('getState', () => { + it('getState when repo is already archived and desired state is not set returns isArchived true shouldArchive false shouldUnarchive false', async () => { + // Arrange + github.rest.repos.get.mockResolvedValue({ data: { archived: true } }) + archive = new Archive(false, github, repo, {}, log) + + // Act + const result = await archive.getState() + + // Assert + expect(result).toEqual({ + isArchived: true, + shouldArchive: false, + shouldUnarchive: false + }) + }) + + it('getState when repo is not archived and desired state is not set returns isArchived false shouldArchive false shouldUnarchive false', async () => { + // Arrange + github.rest.repos.get.mockResolvedValue({ data: { archived: false } }) + archive = new Archive(false, github, repo, {}, log) + + // Act + const result = await archive.getState() + + // Assert + expect(result).toEqual({ + isArchived: false, + shouldArchive: false, + shouldUnarchive: false + }) + }) + + it('getState when repo is archived and desired state is false returns isArchived true shouldArchive false shouldUnarchive true', async () => { + // Arrange + github.rest.repos.get.mockResolvedValue({ data: { archived: true } }) + archive = new Archive(false, github, repo, { archived: false }, log) + + // Act + const result = await archive.getState() + + // Assert + expect(result).toEqual({ + isArchived: true, + shouldArchive: false, + shouldUnarchive: true + }) + }) + }) + describe('sync', () => { beforeEach(() => { archive = new Archive(false, github, repo, settings, log) diff --git a/test/unit/lib/settings.test.js b/test/unit/lib/settings.test.js index b36106518..e102379a6 100644 --- a/test/unit/lib/settings.test.js +++ b/test/unit/lib/settings.test.js @@ -462,4 +462,91 @@ repository: ); }); }); + + describe('updateRepos - archived repo skipping', () => { + const Archive = require('../../../lib/plugins/archive') + + let settings + let mockRepoSync + let originalRepoPlugin + + beforeEach(() => { + // Preserve the original RepoPlugin so it can be restored after each test + originalRepoPlugin = Settings.PLUGINS.repository + + // Replace RepoPlugin with a mock constructor whose sync() we can assert on + mockRepoSync = jest.fn().mockResolvedValue([]) + Settings.PLUGINS.repository = jest.fn().mockImplementation(() => ({ + sync: mockRepoSync + })) + + // Build a Settings instance that will enter the `if (repoConfig)` branch: + // config.repository must be defined so repoConfig is truthy + settings = new Settings( + false, + stubContext, + { owner: 'test-org', repo: 'test-repo' }, + { repository: { name: 'test-repo' } }, + 'main' + ) + + // Pre-set subOrgConfigs so updateRepos() does not call the async getSubOrgConfigs() + settings.subOrgConfigs = {} + + // Pre-set repoConfigs so getRepoOverrideConfig() does not throw on undefined + settings.repoConfigs = {} + }) + + afterEach(() => { + // Restore the real RepoPlugin and all prototype spies + Settings.PLUGINS.repository = originalRepoPlugin + jest.restoreAllMocks() + }) + + it('updateRepos when repo is already archived and not being unarchived does not call RepoPlugin sync', async () => { + // Arrange + jest.spyOn(Archive.prototype, 'getState').mockResolvedValue({ + isArchived: true, + shouldArchive: false, + shouldUnarchive: false + }) + + // Act + await settings.updateRepos({ owner: 'test-org', repo: 'test-repo' }) + + // Assert + expect(mockRepoSync).not.toHaveBeenCalled() + }) + + it('updateRepos when repo is archived but is being unarchived calls RepoPlugin sync', async () => { + // Arrange + jest.spyOn(Archive.prototype, 'getState').mockResolvedValue({ + isArchived: true, + shouldArchive: false, + shouldUnarchive: true + }) + jest.spyOn(Archive.prototype, 'sync').mockResolvedValue([]) + + // Act + await settings.updateRepos({ owner: 'test-org', repo: 'test-repo' }) + + // Assert + expect(mockRepoSync).toHaveBeenCalledTimes(1) + }) + + it('updateRepos when repo is not archived calls RepoPlugin sync', async () => { + // Arrange + jest.spyOn(Archive.prototype, 'getState').mockResolvedValue({ + isArchived: false, + shouldArchive: false, + shouldUnarchive: false + }) + + // Act + await settings.updateRepos({ owner: 'test-org', repo: 'test-repo' }) + + // Assert + expect(mockRepoSync).toHaveBeenCalledTimes(1) + }) + }) // updateRepos - archived repo skipping }) // Settings Tests From 44667a6dd8ae058f4a1ba9280820024c16b0a4cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 22:00:26 +0000 Subject: [PATCH 3/7] build(deps): bump the npm_and_yarn group across 1 directory with 3 updates Bumps the npm_and_yarn group with 3 updates in the / directory: [js-yaml](https://github.com/nodeca/js-yaml), [qs](https://github.com/ljharb/qs) and [shell-quote](https://github.com/ljharb/shell-quote). Updates `js-yaml` from 4.1.1 to 4.2.0 - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/commits) Updates `qs` from 6.15.0 to 6.15.2 - [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/qs/compare/v6.15.0...v6.15.2) Updates `shell-quote` from 1.8.3 to 1.8.4 - [Changelog](https://github.com/ljharb/shell-quote/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/shell-quote/compare/v1.8.3...v1.8.4) --- updated-dependencies: - dependency-name: js-yaml dependency-version: 4.2.0 dependency-type: direct:production dependency-group: npm_and_yarn - dependency-name: qs dependency-version: 6.15.2 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: shell-quote dependency-version: 1.8.4 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- package-lock.json | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index cdb557108..dd836a996 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9938,9 +9938,19 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -11849,9 +11859,9 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -12515,9 +12525,9 @@ } }, "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz", + "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", "dev": true, "license": "MIT", "engines": { From 4ce85a2f8f010b7eb4f94746024ab5ad51f3ef4b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 05:26:29 +0000 Subject: [PATCH 4/7] Initial plan From f69fffa26c4a587ac598cf8212a9be23e1775b83 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 05:28:28 +0000 Subject: [PATCH 5/7] feat: add priorityClassName support to Helm chart --- helm/safe-settings/README.md | 1 + helm/safe-settings/templates/deployment.yaml | 3 +++ helm/safe-settings/values.yaml | 2 ++ 3 files changed, 6 insertions(+) diff --git a/helm/safe-settings/README.md b/helm/safe-settings/README.md index 97cd5b01b..d9c181d0e 100644 --- a/helm/safe-settings/README.md +++ b/helm/safe-settings/README.md @@ -37,6 +37,7 @@ A Helm chart for Kubernetes | nodeSelector | object | `{}` | | | podAnnotations | object | `{}` | | | podSecurityContext | object | `{}` | | +| priorityClassName | string | `""` | Priority class name for the pod. | | replicaCount | int | `1` | | | resources | object | `{}` | | | securityContext.allowPrivilegeEscalation | bool | `false` | | diff --git a/helm/safe-settings/templates/deployment.yaml b/helm/safe-settings/templates/deployment.yaml index cf75673ec..268433149 100644 --- a/helm/safe-settings/templates/deployment.yaml +++ b/helm/safe-settings/templates/deployment.yaml @@ -77,3 +77,6 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName }} + {{- end }} diff --git a/helm/safe-settings/values.yaml b/helm/safe-settings/values.yaml index 99ffa497f..907c3110a 100644 --- a/helm/safe-settings/values.yaml +++ b/helm/safe-settings/values.yaml @@ -118,6 +118,8 @@ tolerations: [] affinity: {} +priorityClassName: "" + deploymentConfig: restrictedRepos: # You can exclude certain repos from safe-settings processing From 53a1c7546af7631ca8602f647245585a5f73029a Mon Sep 17 00:00:00 2001 From: neatcoder <28711376+neatcoder@users.noreply.github.com> Date: Wed, 24 Jun 2026 13:51:28 -0300 Subject: [PATCH 6/7] Add include/exclude repo filters to team settings Team entries are filtered by the same Diffable include/exclude logic that collaborators use, but unlike collaborators those keys were never part of the TeamSettings schema or documented, so editors and linters can't validate them. Mirror the CollaboratorSettings allOf pattern to declare include and exclude on TeamSettings, document both in the teams guide with examples, add a sample, and cover the filter path with unit tests. No runtime changes. --- docs/github-settings/4. teams.md | 28 ++++ docs/sample-settings/settings.yml | 10 ++ schema/dereferenced/repos.json | 222 +++++++++++++++---------- schema/dereferenced/settings.json | 240 +++++++++++++++++----------- schema/dereferenced/suborgs.json | 222 +++++++++++++++---------- schema/repos.json | 25 ++- schema/settings.json | 25 ++- schema/suborgs.json | 25 ++- test/unit/lib/plugins/teams.test.js | 47 ++++++ 9 files changed, 568 insertions(+), 276 deletions(-) diff --git a/docs/github-settings/4. teams.md b/docs/github-settings/4. teams.md index e6085ebcd..1bd035969 100644 --- a/docs/github-settings/4. teams.md +++ b/docs/github-settings/4. teams.md @@ -48,5 +48,33 @@ teams: permission: maintain ``` + + +

 exclude array 

+

Exclude a list of repos for this team. The team is applied to every repo in scope except those whose names match one of these glob patterns.

+ + +```yaml +teams: + - name: SuperFriends + permission: maintain + exclude: + - secret-repo +``` + + + +

 include array 

+

Include a list of repos for this team. The team is applied only to repos whose names match one of these glob patterns.

+ + +```yaml +teams: + - name: SuperFriends + permission: maintain + include: + - public-* +``` + diff --git a/docs/sample-settings/settings.yml b/docs/sample-settings/settings.yml index 1ede6a079..6d12884ec 100644 --- a/docs/sample-settings/settings.yml +++ b/docs/sample-settings/settings.yml @@ -161,6 +161,16 @@ teams: - name: globalteam permission: push visibility: closed + - name: docs-team + permission: pull + # You can include a list of repos for this team and only those repos would have this team + include: + - actions-demo + - name: ops-team + permission: push + # You can exclude a list of repos for this team and all repos except these repos would have this team + exclude: + - actions-demo # Branch protection rules # See https://docs.github.com/en/rest/branches/branch-protection?apiVersion=2026-03-10#update-branch-protection for available options diff --git a/schema/dereferenced/repos.json b/schema/dereferenced/repos.json index 9213456a0..15061706e 100644 --- a/schema/dereferenced/repos.json +++ b/schema/dereferenced/repos.json @@ -400,53 +400,76 @@ "type": "array", "items": { "description": "A team entry", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the team." - }, - "description": { - "type": "string", - "description": "The description of the team." - }, - "maintainers": { - "type": "array", - "description": "List GitHub usernames for organization members who will become team maintainers.", - "items": { - "type": "string" - } - }, - "repo_names": { - "type": "array", - "description": "The full name (e.g., \"organization-name/repository-name\") of repositories to add the team to.", - "items": { - "type": "string" - } - }, - "privacy": { - "type": "string", - "description": "The level of privacy this team should have. The options are: \n**For a non-nested team:** \n * `secret` - only visible to organization owners and members of this team. \n * `closed` - visible to all members of this organization. \nDefault: `secret` \n**For a parent or child team:** \n * `closed` - visible to all members of this organization. \nDefault for child team: `closed`", - "enum": [ - "secret", - "closed" - ] - }, - "notification_setting": { - "type": "string", - "description": "The notification setting the team has chosen. The options are: \n * `notifications_enabled` - team members receive notifications when the team is @mentioned. \n * `notifications_disabled` - no one receives notifications. \nDefault: `notifications_enabled`", - "enum": [ - "notifications_enabled", - "notifications_disabled" + "allOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the team." + }, + "description": { + "type": "string", + "description": "The description of the team." + }, + "maintainers": { + "type": "array", + "description": "List GitHub usernames for organization members who will become team maintainers.", + "items": { + "type": "string" + } + }, + "repo_names": { + "type": "array", + "description": "The full name (e.g., \"organization-name/repository-name\") of repositories to add the team to.", + "items": { + "type": "string" + } + }, + "privacy": { + "type": "string", + "description": "The level of privacy this team should have. The options are: \n**For a non-nested team:** \n * `secret` - only visible to organization owners and members of this team. \n * `closed` - visible to all members of this organization. \nDefault: `secret` \n**For a parent or child team:** \n * `closed` - visible to all members of this organization. \nDefault for child team: `closed`", + "enum": [ + "secret", + "closed" + ] + }, + "notification_setting": { + "type": "string", + "description": "The notification setting the team has chosen. The options are: \n * `notifications_enabled` - team members receive notifications when the team is @mentioned. \n * `notifications_disabled` - no one receives notifications. \nDefault: `notifications_enabled`", + "enum": [ + "notifications_enabled", + "notifications_disabled" + ] + }, + "parent_team_id": { + "type": "integer", + "description": "The ID of a team to set as the parent team." + } + }, + "required": [ + "name" ] }, - "parent_team_id": { - "type": "integer", - "description": "The ID of a team to set as the parent team." + { + "type": "object", + "properties": { + "exclude": { + "description": "You can exclude a list of repos for this team and all repos except these repos would have this team", + "type": "array", + "items": { + "type": "string" + } + }, + "include": { + "description": "You can include a list of repos for this team and only those repos would have this team", + "type": "array", + "items": { + "type": "string" + } + } + } } - }, - "required": [ - "name" ] } }, @@ -1214,53 +1237,76 @@ }, "TeamSettings": { "description": "A team entry", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the team." - }, - "description": { - "type": "string", - "description": "The description of the team." - }, - "maintainers": { - "type": "array", - "description": "List GitHub usernames for organization members who will become team maintainers.", - "items": { - "type": "string" - } - }, - "repo_names": { - "type": "array", - "description": "The full name (e.g., \"organization-name/repository-name\") of repositories to add the team to.", - "items": { - "type": "string" - } - }, - "privacy": { - "type": "string", - "description": "The level of privacy this team should have. The options are: \n**For a non-nested team:** \n * `secret` - only visible to organization owners and members of this team. \n * `closed` - visible to all members of this organization. \nDefault: `secret` \n**For a parent or child team:** \n * `closed` - visible to all members of this organization. \nDefault for child team: `closed`", - "enum": [ - "secret", - "closed" - ] - }, - "notification_setting": { - "type": "string", - "description": "The notification setting the team has chosen. The options are: \n * `notifications_enabled` - team members receive notifications when the team is @mentioned. \n * `notifications_disabled` - no one receives notifications. \nDefault: `notifications_enabled`", - "enum": [ - "notifications_enabled", - "notifications_disabled" + "allOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the team." + }, + "description": { + "type": "string", + "description": "The description of the team." + }, + "maintainers": { + "type": "array", + "description": "List GitHub usernames for organization members who will become team maintainers.", + "items": { + "type": "string" + } + }, + "repo_names": { + "type": "array", + "description": "The full name (e.g., \"organization-name/repository-name\") of repositories to add the team to.", + "items": { + "type": "string" + } + }, + "privacy": { + "type": "string", + "description": "The level of privacy this team should have. The options are: \n**For a non-nested team:** \n * `secret` - only visible to organization owners and members of this team. \n * `closed` - visible to all members of this organization. \nDefault: `secret` \n**For a parent or child team:** \n * `closed` - visible to all members of this organization. \nDefault for child team: `closed`", + "enum": [ + "secret", + "closed" + ] + }, + "notification_setting": { + "type": "string", + "description": "The notification setting the team has chosen. The options are: \n * `notifications_enabled` - team members receive notifications when the team is @mentioned. \n * `notifications_disabled` - no one receives notifications. \nDefault: `notifications_enabled`", + "enum": [ + "notifications_enabled", + "notifications_disabled" + ] + }, + "parent_team_id": { + "type": "integer", + "description": "The ID of a team to set as the parent team." + } + }, + "required": [ + "name" ] }, - "parent_team_id": { - "type": "integer", - "description": "The ID of a team to set as the parent team." + { + "type": "object", + "properties": { + "exclude": { + "description": "You can exclude a list of repos for this team and all repos except these repos would have this team", + "type": "array", + "items": { + "type": "string" + } + }, + "include": { + "description": "You can include a list of repos for this team and only those repos would have this team", + "type": "array", + "items": { + "type": "string" + } + } + } } - }, - "required": [ - "name" ] }, "MilestoneSettings": { diff --git a/schema/dereferenced/settings.json b/schema/dereferenced/settings.json index 4dcdf0eb6..b118f39f7 100644 --- a/schema/dereferenced/settings.json +++ b/schema/dereferenced/settings.json @@ -421,62 +421,85 @@ "type": "array", "items": { "description": "A team entry", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the team." - }, - "description": { - "type": "string", - "description": "The description of the team." - }, - "maintainers": { - "type": "array", - "description": "List GitHub usernames for organization members who will become team maintainers.", - "items": { - "type": "string" - } - }, - "repo_names": { - "type": "array", - "description": "The full name (e.g., \"organization-name/repository-name\") of repositories to add the team to.", - "items": { - "type": "string" - } - }, - "privacy": { - "type": "string", - "description": "The level of privacy this team should have. The options are: \n**For a non-nested team:** \n * `secret` - only visible to organization owners and members of this team. \n * `closed` - visible to all members of this organization. \nDefault: `secret` \n**For a parent or child team:** \n * `closed` - visible to all members of this organization. \nDefault for child team: `closed`", - "enum": [ - "secret", - "closed" - ] - }, - "notification_setting": { - "type": "string", - "description": "The notification setting the team has chosen. The options are: \n * `notifications_enabled` - team members receive notifications when the team is @mentioned. \n * `notifications_disabled` - no one receives notifications. \nDefault: `notifications_enabled`", - "enum": [ - "notifications_enabled", - "notifications_disabled" + "allOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the team." + }, + "description": { + "type": "string", + "description": "The description of the team." + }, + "maintainers": { + "type": "array", + "description": "List GitHub usernames for organization members who will become team maintainers.", + "items": { + "type": "string" + } + }, + "repo_names": { + "type": "array", + "description": "The full name (e.g., \"organization-name/repository-name\") of repositories to add the team to.", + "items": { + "type": "string" + } + }, + "privacy": { + "type": "string", + "description": "The level of privacy this team should have. The options are: \n**For a non-nested team:** \n * `secret` - only visible to organization owners and members of this team. \n * `closed` - visible to all members of this organization. \nDefault: `secret` \n**For a parent or child team:** \n * `closed` - visible to all members of this organization. \nDefault for child team: `closed`", + "enum": [ + "secret", + "closed" + ] + }, + "notification_setting": { + "type": "string", + "description": "The notification setting the team has chosen. The options are: \n * `notifications_enabled` - team members receive notifications when the team is @mentioned. \n * `notifications_disabled` - no one receives notifications. \nDefault: `notifications_enabled`", + "enum": [ + "notifications_enabled", + "notifications_disabled" + ] + }, + "permission": { + "type": "string", + "description": "**Closing down notice**. The permission that new repositories will be added to the team with when none is specified.", + "enum": [ + "pull", + "push" + ], + "default": "pull" + }, + "parent_team_id": { + "type": "integer", + "description": "The ID of a team to set as the parent team." + } + }, + "required": [ + "name" ] }, - "permission": { - "type": "string", - "description": "**Closing down notice**. The permission that new repositories will be added to the team with when none is specified.", - "enum": [ - "pull", - "push" - ], - "default": "pull" - }, - "parent_team_id": { - "type": "integer", - "description": "The ID of a team to set as the parent team." + { + "type": "object", + "properties": { + "exclude": { + "description": "You can exclude a list of repos for this team and all repos except these repos would have this team", + "type": "array", + "items": { + "type": "string" + } + }, + "include": { + "description": "You can include a list of repos for this team and only those repos would have this team", + "type": "array", + "items": { + "type": "string" + } + } + } } - }, - "required": [ - "name" ] } }, @@ -2392,53 +2415,76 @@ }, "TeamSettings": { "description": "A team entry", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the team." - }, - "description": { - "type": "string", - "description": "The description of the team." - }, - "maintainers": { - "type": "array", - "description": "List GitHub usernames for organization members who will become team maintainers.", - "items": { - "type": "string" - } - }, - "repo_names": { - "type": "array", - "description": "The full name (e.g., \"organization-name/repository-name\") of repositories to add the team to.", - "items": { - "type": "string" - } - }, - "privacy": { - "type": "string", - "description": "The level of privacy this team should have. The options are: \n**For a non-nested team:** \n * `secret` - only visible to organization owners and members of this team. \n * `closed` - visible to all members of this organization. \nDefault: `secret` \n**For a parent or child team:** \n * `closed` - visible to all members of this organization. \nDefault for child team: `closed`", - "enum": [ - "secret", - "closed" - ] - }, - "notification_setting": { - "type": "string", - "description": "The notification setting the team has chosen. The options are: \n * `notifications_enabled` - team members receive notifications when the team is @mentioned. \n * `notifications_disabled` - no one receives notifications. \nDefault: `notifications_enabled`", - "enum": [ - "notifications_enabled", - "notifications_disabled" + "allOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the team." + }, + "description": { + "type": "string", + "description": "The description of the team." + }, + "maintainers": { + "type": "array", + "description": "List GitHub usernames for organization members who will become team maintainers.", + "items": { + "type": "string" + } + }, + "repo_names": { + "type": "array", + "description": "The full name (e.g., \"organization-name/repository-name\") of repositories to add the team to.", + "items": { + "type": "string" + } + }, + "privacy": { + "type": "string", + "description": "The level of privacy this team should have. The options are: \n**For a non-nested team:** \n * `secret` - only visible to organization owners and members of this team. \n * `closed` - visible to all members of this organization. \nDefault: `secret` \n**For a parent or child team:** \n * `closed` - visible to all members of this organization. \nDefault for child team: `closed`", + "enum": [ + "secret", + "closed" + ] + }, + "notification_setting": { + "type": "string", + "description": "The notification setting the team has chosen. The options are: \n * `notifications_enabled` - team members receive notifications when the team is @mentioned. \n * `notifications_disabled` - no one receives notifications. \nDefault: `notifications_enabled`", + "enum": [ + "notifications_enabled", + "notifications_disabled" + ] + }, + "parent_team_id": { + "type": "integer", + "description": "The ID of a team to set as the parent team." + } + }, + "required": [ + "name" ] }, - "parent_team_id": { - "type": "integer", - "description": "The ID of a team to set as the parent team." + { + "type": "object", + "properties": { + "exclude": { + "description": "You can exclude a list of repos for this team and all repos except these repos would have this team", + "type": "array", + "items": { + "type": "string" + } + }, + "include": { + "description": "You can include a list of repos for this team and only those repos would have this team", + "type": "array", + "items": { + "type": "string" + } + } + } } - }, - "required": [ - "name" ] }, "MilestoneSettings": { diff --git a/schema/dereferenced/suborgs.json b/schema/dereferenced/suborgs.json index 0267bf7a8..5824a4879 100644 --- a/schema/dereferenced/suborgs.json +++ b/schema/dereferenced/suborgs.json @@ -434,53 +434,76 @@ "type": "array", "items": { "description": "A team entry", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the team." - }, - "description": { - "type": "string", - "description": "The description of the team." - }, - "maintainers": { - "type": "array", - "description": "List GitHub usernames for organization members who will become team maintainers.", - "items": { - "type": "string" - } - }, - "repo_names": { - "type": "array", - "description": "The full name (e.g., \"organization-name/repository-name\") of repositories to add the team to.", - "items": { - "type": "string" - } - }, - "privacy": { - "type": "string", - "description": "The level of privacy this team should have. The options are: \n**For a non-nested team:** \n * `secret` - only visible to organization owners and members of this team. \n * `closed` - visible to all members of this organization. \nDefault: `secret` \n**For a parent or child team:** \n * `closed` - visible to all members of this organization. \nDefault for child team: `closed`", - "enum": [ - "secret", - "closed" - ] - }, - "notification_setting": { - "type": "string", - "description": "The notification setting the team has chosen. The options are: \n * `notifications_enabled` - team members receive notifications when the team is @mentioned. \n * `notifications_disabled` - no one receives notifications. \nDefault: `notifications_enabled`", - "enum": [ - "notifications_enabled", - "notifications_disabled" + "allOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the team." + }, + "description": { + "type": "string", + "description": "The description of the team." + }, + "maintainers": { + "type": "array", + "description": "List GitHub usernames for organization members who will become team maintainers.", + "items": { + "type": "string" + } + }, + "repo_names": { + "type": "array", + "description": "The full name (e.g., \"organization-name/repository-name\") of repositories to add the team to.", + "items": { + "type": "string" + } + }, + "privacy": { + "type": "string", + "description": "The level of privacy this team should have. The options are: \n**For a non-nested team:** \n * `secret` - only visible to organization owners and members of this team. \n * `closed` - visible to all members of this organization. \nDefault: `secret` \n**For a parent or child team:** \n * `closed` - visible to all members of this organization. \nDefault for child team: `closed`", + "enum": [ + "secret", + "closed" + ] + }, + "notification_setting": { + "type": "string", + "description": "The notification setting the team has chosen. The options are: \n * `notifications_enabled` - team members receive notifications when the team is @mentioned. \n * `notifications_disabled` - no one receives notifications. \nDefault: `notifications_enabled`", + "enum": [ + "notifications_enabled", + "notifications_disabled" + ] + }, + "parent_team_id": { + "type": "integer", + "description": "The ID of a team to set as the parent team." + } + }, + "required": [ + "name" ] }, - "parent_team_id": { - "type": "integer", - "description": "The ID of a team to set as the parent team." + { + "type": "object", + "properties": { + "exclude": { + "description": "You can exclude a list of repos for this team and all repos except these repos would have this team", + "type": "array", + "items": { + "type": "string" + } + }, + "include": { + "description": "You can include a list of repos for this team and only those repos would have this team", + "type": "array", + "items": { + "type": "string" + } + } + } } - }, - "required": [ - "name" ] } }, @@ -1248,53 +1271,76 @@ }, "TeamSettings": { "description": "A team entry", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the team." - }, - "description": { - "type": "string", - "description": "The description of the team." - }, - "maintainers": { - "type": "array", - "description": "List GitHub usernames for organization members who will become team maintainers.", - "items": { - "type": "string" - } - }, - "repo_names": { - "type": "array", - "description": "The full name (e.g., \"organization-name/repository-name\") of repositories to add the team to.", - "items": { - "type": "string" - } - }, - "privacy": { - "type": "string", - "description": "The level of privacy this team should have. The options are: \n**For a non-nested team:** \n * `secret` - only visible to organization owners and members of this team. \n * `closed` - visible to all members of this organization. \nDefault: `secret` \n**For a parent or child team:** \n * `closed` - visible to all members of this organization. \nDefault for child team: `closed`", - "enum": [ - "secret", - "closed" - ] - }, - "notification_setting": { - "type": "string", - "description": "The notification setting the team has chosen. The options are: \n * `notifications_enabled` - team members receive notifications when the team is @mentioned. \n * `notifications_disabled` - no one receives notifications. \nDefault: `notifications_enabled`", - "enum": [ - "notifications_enabled", - "notifications_disabled" + "allOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the team." + }, + "description": { + "type": "string", + "description": "The description of the team." + }, + "maintainers": { + "type": "array", + "description": "List GitHub usernames for organization members who will become team maintainers.", + "items": { + "type": "string" + } + }, + "repo_names": { + "type": "array", + "description": "The full name (e.g., \"organization-name/repository-name\") of repositories to add the team to.", + "items": { + "type": "string" + } + }, + "privacy": { + "type": "string", + "description": "The level of privacy this team should have. The options are: \n**For a non-nested team:** \n * `secret` - only visible to organization owners and members of this team. \n * `closed` - visible to all members of this organization. \nDefault: `secret` \n**For a parent or child team:** \n * `closed` - visible to all members of this organization. \nDefault for child team: `closed`", + "enum": [ + "secret", + "closed" + ] + }, + "notification_setting": { + "type": "string", + "description": "The notification setting the team has chosen. The options are: \n * `notifications_enabled` - team members receive notifications when the team is @mentioned. \n * `notifications_disabled` - no one receives notifications. \nDefault: `notifications_enabled`", + "enum": [ + "notifications_enabled", + "notifications_disabled" + ] + }, + "parent_team_id": { + "type": "integer", + "description": "The ID of a team to set as the parent team." + } + }, + "required": [ + "name" ] }, - "parent_team_id": { - "type": "integer", - "description": "The ID of a team to set as the parent team." + { + "type": "object", + "properties": { + "exclude": { + "description": "You can exclude a list of repos for this team and all repos except these repos would have this team", + "type": "array", + "items": { + "type": "string" + } + }, + "include": { + "description": "You can include a list of repos for this team and only those repos would have this team", + "type": "array", + "items": { + "type": "string" + } + } + } } - }, - "required": [ - "name" ] }, "MilestoneSettings": { diff --git a/schema/repos.json b/schema/repos.json index 3a7c51301..2d7fa869d 100644 --- a/schema/repos.json +++ b/schema/repos.json @@ -190,7 +190,30 @@ }, "TeamSettings": { "description": "A team entry", - "$ref": "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.2026-03-10.json#/paths/~1orgs~1{org}~1teams/post/requestBody/content/application~1json/schema" + "allOf": [ + { + "$ref": "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.2026-03-10.json#/paths/~1orgs~1{org}~1teams/post/requestBody/content/application~1json/schema" + }, + { + "type": "object", + "properties": { + "exclude": { + "description": "You can exclude a list of repos for this team and all repos except these repos would have this team", + "type": "array", + "items": { + "type": "string" + } + }, + "include": { + "description": "You can include a list of repos for this team and only those repos would have this team", + "type": "array", + "items": { + "type": "string" + } + } + } + } + ] }, "MilestoneSettings": { "description": "A milestone entry", diff --git a/schema/settings.json b/schema/settings.json index 59d662d50..11d749127 100644 --- a/schema/settings.json +++ b/schema/settings.json @@ -197,7 +197,30 @@ }, "TeamSettings": { "description": "A team entry", - "$ref": "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.2026-03-10.json#/paths/~1orgs~1{org}~1teams/post/requestBody/content/application~1json/schema" + "allOf": [ + { + "$ref": "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.2026-03-10.json#/paths/~1orgs~1{org}~1teams/post/requestBody/content/application~1json/schema" + }, + { + "type": "object", + "properties": { + "exclude": { + "description": "You can exclude a list of repos for this team and all repos except these repos would have this team", + "type": "array", + "items": { + "type": "string" + } + }, + "include": { + "description": "You can include a list of repos for this team and only those repos would have this team", + "type": "array", + "items": { + "type": "string" + } + } + } + } + ] }, "MilestoneSettings": { "description": "A milestone entry", diff --git a/schema/suborgs.json b/schema/suborgs.json index 3a3c79def..23a408d1b 100644 --- a/schema/suborgs.json +++ b/schema/suborgs.json @@ -224,7 +224,30 @@ }, "TeamSettings": { "description": "A team entry", - "$ref": "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.2026-03-10.json#/paths/~1orgs~1{org}~1teams/post/requestBody/content/application~1json/schema" + "allOf": [ + { + "$ref": "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.2026-03-10.json#/paths/~1orgs~1{org}~1teams/post/requestBody/content/application~1json/schema" + }, + { + "type": "object", + "properties": { + "exclude": { + "description": "You can exclude a list of repos for this team and all repos except these repos would have this team", + "type": "array", + "items": { + "type": "string" + } + }, + "include": { + "description": "You can include a list of repos for this team and only those repos would have this team", + "type": "array", + "items": { + "type": "string" + } + } + } + } + ] }, "MilestoneSettings": { "description": "A milestone entry", diff --git a/test/unit/lib/plugins/teams.test.js b/test/unit/lib/plugins/teams.test.js index de16965a6..1ae9b569c 100644 --- a/test/unit/lib/plugins/teams.test.js +++ b/test/unit/lib/plugins/teams.test.js @@ -103,4 +103,51 @@ describe('Teams', () => { ) } }) + + describe('filtering teams by include/exclude', () => { + beforeEach(() => { + github.rest.repos.listTeams.mockResolvedValue({ data: [] }) + }) + + it('does not add a team when the repo matches an exclude glob', async () => { + const plugin = configure([ + { name: addedTeamName, permission: 'pull', exclude: ['test*'] } + ]) + + await plugin.sync() + + expect(github.rest.teams.addOrUpdateRepoPermissionsInOrg).not.toHaveBeenCalled() + }) + + it('does not add a team when the repo is not in an include glob', async () => { + const plugin = configure([ + { name: addedTeamName, permission: 'pull', include: ['other-*'] } + ]) + + await plugin.sync() + + expect(github.rest.teams.addOrUpdateRepoPermissionsInOrg).not.toHaveBeenCalled() + }) + + it('adds a team when the repo matches an include glob', async () => { + when(github.rest.teams.getByName) + .calledWith({ org, team_slug: addedTeamName }) + .mockResolvedValue({ data: { id: addedTeamId } }) + + const plugin = configure([ + { name: addedTeamName, permission: 'pull', include: ['test*'] } + ]) + + await plugin.sync() + + expect(github.rest.teams.addOrUpdateRepoPermissionsInOrg).toHaveBeenCalledWith({ + org, + team_id: addedTeamId, + team_slug: addedTeamName, + owner: org, + repo: 'test', + permission: 'pull' + }) + }) + }) }) From dbea7c17590df2406a8e978bd8f2e32d595157ef Mon Sep 17 00:00:00 2001 From: "Zeyu (Zayne) Zhang" Date: Sat, 8 Aug 2026 17:03:54 +0800 Subject: [PATCH 7/7] feat: add hacktron repo config --- .github/repos/hacktron.yml | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/repos/hacktron.yml diff --git a/.github/repos/hacktron.yml b/.github/repos/hacktron.yml new file mode 100644 index 000000000..d7533b77c --- /dev/null +++ b/.github/repos/hacktron.yml @@ -0,0 +1,44 @@ +repository: + name: hacktron + private: true + allow_squash_merge: true + allow_merge_commit: true + allow_rebase_merge: true + +branches: + - name: main + protection: + required_pull_request_reviews: + required_approving_review_count: 1 + dismiss_stale_reviews: true + require_code_owner_reviews: true + require_last_push_approval: true + bypass_pull_request_allowances: + users: [] + teams: + - core + apps: [] + required_status_checks: null + enforce_admins: true + restrictions: + users: [] + teams: + - core + apps: [] + required_linear_history: false + allow_force_pushes: true + allow_deletions: false + + - name: staging + protection: + required_pull_request_reviews: + required_approving_review_count: 1 + dismiss_stale_reviews: false + require_code_owner_reviews: false + require_last_push_approval: false + required_status_checks: null + enforce_admins: false + restrictions: null + required_linear_history: false + allow_force_pushes: false + allow_deletions: false