diff --git a/changelog/issue-7776.md b/changelog/issue-7776.md new file mode 100644 index 00000000000..092a34d2200 --- /dev/null +++ b/changelog/issue-7776.md @@ -0,0 +1,5 @@ +audience: developers +level: patch +reference: issue 7776 +--- +Fixed schema to allow `.` in GitHub repository names. diff --git a/clients/client-go/tcgithub/types.go b/clients/client-go/tcgithub/types.go index b664e0ee9cf..6d3083f1668 100644 --- a/clients/client-go/tcgithub/types.go +++ b/clients/client-go/tcgithub/types.go @@ -26,7 +26,7 @@ type ( // Github organization associated with the build. // - // Syntax: ^([a-zA-Z0-9-_%]*)$ + // Syntax: ^([a-zA-Z0-9-_.%]*)$ // Min length: 1 // Max length: 100 Organization string `json:"organization"` @@ -36,7 +36,7 @@ type ( // Github repository associated with the build. // - // Syntax: ^([a-zA-Z0-9-_%]*)$ + // Syntax: ^([a-zA-Z0-9-_.%]*)$ // Min length: 1 // Max length: 100 Repository string `json:"repository"` diff --git a/clients/client-go/tcgithubevents/types.go b/clients/client-go/tcgithubevents/types.go index b51b01ff1bc..ac5e214e581 100644 --- a/clients/client-go/tcgithubevents/types.go +++ b/clients/client-go/tcgithubevents/types.go @@ -39,14 +39,14 @@ type ( // The GitHub `organization` which had an event. // - // Syntax: ^([a-zA-Z0-9-_%]*)$ + // Syntax: ^([a-zA-Z0-9-_.%]*)$ // Min length: 1 // Max length: 100 Organization string `json:"organization"` // The GitHub `repository` which had an event. // - // Syntax: ^([a-zA-Z0-9-_%]*)$ + // Syntax: ^([a-zA-Z0-9-_.%]*)$ // Min length: 1 // Max length: 100 Repository string `json:"repository"` @@ -87,14 +87,14 @@ type ( // The GitHub `organization` which had an event. // - // Syntax: ^([a-zA-Z0-9-_%]*)$ + // Syntax: ^([a-zA-Z0-9-_.%]*)$ // Min length: 1 // Max length: 100 Organization string `json:"organization"` // The GitHub `repository` which had an event. // - // Syntax: ^([a-zA-Z0-9-_%]*)$ + // Syntax: ^([a-zA-Z0-9-_.%]*)$ // Min length: 1 // Max length: 100 Repository string `json:"repository"` @@ -138,14 +138,14 @@ type ( // The GitHub `organization` which had an event. // - // Syntax: ^([a-zA-Z0-9-_%]*)$ + // Syntax: ^([a-zA-Z0-9-_.%]*)$ // Min length: 1 // Max length: 100 Organization string `json:"organization"` // The GitHub `repository` which had an event. // - // Syntax: ^([a-zA-Z0-9-_%]*)$ + // Syntax: ^([a-zA-Z0-9-_.%]*)$ // Min length: 1 // Max length: 100 Repository string `json:"repository"` @@ -189,14 +189,14 @@ type ( // The GitHub `organization` which had an event. // - // Syntax: ^([a-zA-Z0-9-_%]*)$ + // Syntax: ^([a-zA-Z0-9-_.%]*)$ // Min length: 1 // Max length: 100 Organization string `json:"organization"` // The GitHub `repository` which had an event. // - // Syntax: ^([a-zA-Z0-9-_%]*)$ + // Syntax: ^([a-zA-Z0-9-_.%]*)$ // Min length: 1 // Max length: 100 Repository string `json:"repository"` @@ -218,14 +218,14 @@ type ( // The GitHub `organization` which had an event. // - // Syntax: ^([a-zA-Z0-9-_%]*)$ + // Syntax: ^([a-zA-Z0-9-_.%]*)$ // Min length: 1 // Max length: 100 Organization string `json:"organization"` // The GitHub `repository` which had an event. // - // Syntax: ^([a-zA-Z0-9-_%]*)$ + // Syntax: ^([a-zA-Z0-9-_.%]*)$ // Min length: 1 // Max length: 100 Repository string `json:"repository"` diff --git a/generated/references.json b/generated/references.json index 9c0cc35bf5c..a5d500e4e33 100644 --- a/generated/references.json +++ b/generated/references.json @@ -7940,14 +7940,14 @@ "description": "The GitHub `organization` which had an event.\n", "maxLength": 100, "minLength": 1, - "pattern": "^([a-zA-Z0-9-_%]*)$", + "pattern": "^([a-zA-Z0-9-_.%]*)$", "type": "string" }, "repository": { "description": "The GitHub `repository` which had an event.\n", "maxLength": 100, "minLength": 1, - "pattern": "^([a-zA-Z0-9-_%]*)$", + "pattern": "^([a-zA-Z0-9-_.%]*)$", "type": "string" }, "taskGroupId": { @@ -8230,14 +8230,14 @@ "description": "The GitHub `organization` which had an event.\n", "maxLength": 100, "minLength": 1, - "pattern": "^([a-zA-Z0-9-_%]*)$", + "pattern": "^([a-zA-Z0-9-_.%]*)$", "type": "string" }, "repository": { "description": "The GitHub `repository` which had an event.\n", "maxLength": 100, "minLength": 1, - "pattern": "^([a-zA-Z0-9-_%]*)$", + "pattern": "^([a-zA-Z0-9-_.%]*)$", "type": "string" }, "tasks_for": { @@ -8301,14 +8301,14 @@ "description": "The GitHub `organization` which had an event.\n", "maxLength": 100, "minLength": 1, - "pattern": "^([a-zA-Z0-9-_%]*)$", + "pattern": "^([a-zA-Z0-9-_.%]*)$", "type": "string" }, "repository": { "description": "The GitHub `repository` which had an event.\n", "maxLength": 100, "minLength": 1, - "pattern": "^([a-zA-Z0-9-_%]*)$", + "pattern": "^([a-zA-Z0-9-_.%]*)$", "type": "string" }, "tasks_for": { @@ -8369,14 +8369,14 @@ "description": "The GitHub `organization` which had an event.\n", "maxLength": 100, "minLength": 1, - "pattern": "^([a-zA-Z0-9-_%]*)$", + "pattern": "^([a-zA-Z0-9-_.%]*)$", "type": "string" }, "repository": { "description": "The GitHub `repository` which had an event.\n", "maxLength": 100, "minLength": 1, - "pattern": "^([a-zA-Z0-9-_%]*)$", + "pattern": "^([a-zA-Z0-9-_.%]*)$", "type": "string" }, "tasks_for": { @@ -8443,14 +8443,14 @@ "description": "The GitHub `organization` which had an event.\n", "maxLength": 100, "minLength": 1, - "pattern": "^([a-zA-Z0-9-_%]*)$", + "pattern": "^([a-zA-Z0-9-_.%]*)$", "type": "string" }, "repository": { "description": "The GitHub `repository` which had an event.\n", "maxLength": 100, "minLength": 1, - "pattern": "^([a-zA-Z0-9-_%]*)$", + "pattern": "^([a-zA-Z0-9-_.%]*)$", "type": "string" }, "tasks_for": { @@ -8581,7 +8581,7 @@ "description": "Github organization associated with the build.", "maxLength": 100, "minLength": 1, - "pattern": "^([a-zA-Z0-9-_%]*)$", + "pattern": "^([a-zA-Z0-9-_.%]*)$", "type": "string" }, "pullRequestNumber": { @@ -8592,7 +8592,7 @@ "description": "Github repository associated with the build.", "maxLength": 100, "minLength": 1, - "pattern": "^([a-zA-Z0-9-_%]*)$", + "pattern": "^([a-zA-Z0-9-_.%]*)$", "type": "string" }, "sha": { diff --git a/services/github/schemas/constants.yml b/services/github/schemas/constants.yml index 020abaeedc4..0387ffff4f5 100644 --- a/services/github/schemas/constants.yml +++ b/services/github/schemas/constants.yml @@ -3,8 +3,10 @@ # all common identifiers. It's not personal, it's just that without these # limitation, the identifiers won't be useful as routing keys in RabbitMQ # topic exchanges. Specifically, the length limitation and the fact that -# identifiers can't contain dots `.` is critical. -github-identifier-pattern: "^([a-zA-Z0-9-_%]*)$" +# GitHub service automatically sanitizes identifiers by replacing any dots `.` with another +# character, so dots are allowed but transformed. + +github-identifier-pattern: "^([a-zA-Z0-9-_.%]*)$" github-identifier-min-length: 1 github-identifier-max-length: 100 github-guid-pattern: "^[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}$" diff --git a/services/github/test/github_Identifier_Pattern_test.js b/services/github/test/github_Identifier_Pattern_test.js new file mode 100644 index 00000000000..68104480d50 --- /dev/null +++ b/services/github/test/github_Identifier_Pattern_test.js @@ -0,0 +1,75 @@ +import helper from './helper.js'; +import assert from 'assert'; +import fs from 'fs'; +import yaml from 'js-yaml'; + +helper.secrets.mockSuite('github-identifier-pattern', [], function(mock, skipping) { + suiteSetup(async function() { + if (skipping()) return; + const constantsYaml = fs.readFileSync('../schemas/constants.yml', 'utf8'); + const constants = yaml.load(constantsYaml); + + this.githubPattern = new RegExp(constants['github-identifier-pattern']); + this.minLength = constants['github-identifier-min-length']; + this.maxLength = constants['github-identifier-max-length']; + }); + + function testLengthConstraints(id) { + assert.ok(id.length >= this.minLength, `"${id}" is shorter than min length`); + assert.ok(id.length <= this.maxLength, `"${id}" is longer than max length`); + } + + test('valid GitHub identifiers', function() { + const validIdentifiers = [ + 'abc123', + 'org-name', + 'my_repo', + 'repo123', + 'ORG-Repo', + 'abc.def', + 'name_with_underscores', + 'name%repo', + 'percent%encoded', + 'a', + 'a'.repeat(100), + ]; + + validIdentifiers.forEach(id => { + assert.ok(this.githubPattern.test(id), `Expected "${id}" to match github-identifier-pattern`); + testLengthConstraints.call(this, id); + }); + }); + + test('invalid GitHub identifiers', function() { + const invalidIdentifiers = [ + 'with space', + 'repo!', + 'abc$123', + '@org/repo', + 'org/repo', + 'org//repo', + 'repo#1', + '😀emoji', + 'a'.repeat(101), + ]; + + invalidIdentifiers.forEach(id => { + const matchesPattern = this.githubPattern.test(id); + const exceedsLength = id.length > this.maxLength; + assert.ok(!matchesPattern || exceedsLength, `Expected "${id}" to be invalid`); + }); + }); + + test('edge cases for GitHub identifiers', function() { + const edgeCases = [ + 'a-b_c', + 'repo-underscore_only_', + 'repo-dash-only-', + 'abc.def%ghi', + ]; + edgeCases.forEach(id => { + assert.ok(this.githubPattern.test(id), `Expected "${id}" to match github-identifier-pattern`); + testLengthConstraints.call(this, id); + }); + }); +});