From 2bd79f1b1fa2f8c746a85f352f5a7f9f266d9e2b Mon Sep 17 00:00:00 2001 From: Eli <88557639+lishaduck@users.noreply.github.com> Date: Sun, 10 Nov 2024 20:08:14 -0600 Subject: [PATCH 1/3] ci: use actions' token GHA provides a token itself, we don't need to generate one. This is more-fine grained, easier to change if needed, and more secure. I think the existing `contents: read` is sufficient, but it might not be. We'll see. --- .github/workflows/test.yml | 2 ++ turbo.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8c0658076..eb67e0dd3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -94,3 +94,5 @@ jobs: - name: Run tests run: npm test + env: + AUTH_GITHUB: ${{ secrets.GITHUB_TOKEN }} diff --git a/turbo.json b/turbo.json index 9b3fb25b8..c617777ac 100644 --- a/turbo.json +++ b/turbo.json @@ -1,7 +1,7 @@ { "$schema": "https://turbo.build/schema.json", "globalEnv": ["NO_COLOR", "LOCAL_ELM_REVIEW_SRC", "ELM_HOME"], - "globalPassThroughEnv": ["GITHUB_TOKEN", "AUTH_GITHUB"], + "globalPassThroughEnv": ["AUTH_GITHUB"], "tasks": { "elm-format": { "inputs": [ From 3cb829d7f40eda05d46c6220f1162bde96b803c0 Mon Sep 17 00:00:00 2001 From: Eli <88557639+lishaduck@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:51:30 -0600 Subject: [PATCH 2/3] fix: update github auth to not require a username --- .github/workflows/test.yml | 2 +- lib/flags.js | 2 +- lib/options.js | 23 ++++++++----------- lib/remote-template.js | 13 +++++------ lib/types/options.ts | 3 +-- test/flags.test.js | 2 +- test/run.sh | 2 +- .../flags/github-auth-bad-argument.txt | 2 +- turbo.json | 4 ++-- 9 files changed, 23 insertions(+), 30 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eb67e0dd3..16548e097 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -95,4 +95,4 @@ jobs: - name: Run tests run: npm test env: - AUTH_GITHUB: ${{ secrets.GITHUB_TOKEN }} + AUTH_GITHUB: ${{ github.token }} diff --git a/lib/flags.js b/lib/flags.js index 2cbed8246..2fe0e4139 100644 --- a/lib/flags.js +++ b/lib/flags.js @@ -23,7 +23,7 @@ const gitHubAuthFlag = { 'Follow https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token to create an API token. The API token needs access to public repositories.', '', 'Then use the flag like this:', - chalk.greenBright(' --github-auth=my-user-name:abcdef01234567890') + chalk.greenBright(' --github-auth=github_pat_abcdef01234567890') ] }; diff --git a/lib/options.js b/lib/options.js index 969fec081..4a1c8d188 100644 --- a/lib/options.js +++ b/lib/options.js @@ -181,12 +181,7 @@ try re-running it with ${chalk.cyan('--elmjson ')}.`, const forTests = args['FOR-TESTS']; - // eslint-disable-next-line unicorn/no-useless-undefined -- Bad TS type. - const {gitHubUser = undefined, gitHubPassword = undefined} = args[ - 'github-auth' - ] - ? parseGitHubAuth(subcommand, args['github-auth']) - : {}; + const gitHubPat = parseGitHubAuth(subcommand, args['github-auth']); const localElmReviewSrc = process.env.LOCAL_ELM_REVIEW_SRC; @@ -324,9 +319,8 @@ try re-running it with ${chalk.cyan('--elmjson ')}.`, resultCachePath: (appHash) => path.join(elmStuffFolder(), 'result-cache', appHash), - // GitHub tokens - gitHubUser, - gitHubPassword + // GitHub token + gitHubPat }; } @@ -653,12 +647,14 @@ I recommend you try to gain network access and try again.`, /** * @param {Subcommand | null} subcommand - * @param {string} gitHubAuth - * @returns {{gitHubUser: string | undefined, gitHubPassword: string | undefined} | never} + * @param {string | undefined} gitHubAuth + * @returns {string | undefined | never} */ function parseGitHubAuth(subcommand, gitHubAuth) { + if (gitHubAuth === undefined) return; + const split = gitHubAuth.split(':'); - if (split.length !== 2) { + if (split.length !== 2 && split.length !== 1) { reportErrorAndExit( new ErrorMessage.CustomError( 'INVALID FLAG ARGUMENT', @@ -673,8 +669,7 @@ ${Flags.buildFlag(subcommand, Flags.gitHubAuthFlag)}` ); } - const [gitHubUser, gitHubPassword] = split; - return {gitHubUser, gitHubPassword}; + return split.length === 2 ? split[1] : split[0]; } /** diff --git a/lib/remote-template.js b/lib/remote-template.js index d9285ab64..08eeaa731 100644 --- a/lib/remote-template.js +++ b/lib/remote-template.js @@ -203,7 +203,7 @@ const rateLimitErrorMessage = { message: `It looks like you exceeded the GitHub rate limit by using "--template" too many times, this will likely last for 30 minutes. -In the meantime, you can use \`--github-auth your-github-username:your-api-token\`. +In the meantime, you can use \`--github-auth=your-api-token\`. Follow this guide: https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token to create an API token, and give it access to public repositories. To avoid this problem and to make the review process faster, consider setting up @@ -358,12 +358,11 @@ async function downloadFile(url, dest) { * @returns {Promise} */ async function makeGitHubApiRequest(options, url, handleNotFound) { - /** @type {OptionsOfJSONResponseBody}} */ - const parameters = {responseType: 'json'}; - if (options.gitHubUser && options.gitHubPassword) { - parameters.username = options.gitHubUser; - parameters.password = options.gitHubPassword; - } + /** @type {OptionsOfJSONResponseBody} */ + const parameters = { + responseType: 'json', + headers: {Authorization: `BEARER: ${options.gitHubPat}`} + }; Debug.log(`Making API request to GitHub: ${url}`); try { diff --git a/lib/types/options.ts b/lib/types/options.ts index 4abdfabde..51af36176 100644 --- a/lib/types/options.ts +++ b/lib/types/options.ts @@ -60,8 +60,7 @@ export type Options = OptionsBase & { fileCachePath: () => Path; resultCachePath: (appHash: AppHash) => Path; - gitHubUser: string | undefined; - gitHubPassword: string | undefined; + gitHubPat?: string | undefined; }; export type ReviewOptions = Options & { diff --git a/test/flags.test.js b/test/flags.test.js index 1af25be5e..97e0dce21 100644 --- a/test/flags.test.js +++ b/test/flags.test.js @@ -96,7 +96,7 @@ test('Running new-package --compiler without an argument', async () => { }); test('Running --github-auth with a bad value', async () => { - const output = await TestCli.runAndExpectError('--github-auth=bad'); + const output = await TestCli.runAndExpectError('--github-auth=::'); expect(output).toMatchFile(testName('github-auth-bad-argument')); }); diff --git a/test/run.sh b/test/run.sh index 40102ec0a..cb18b93cf 100755 --- a/test/run.sh +++ b/test/run.sh @@ -14,7 +14,7 @@ replace_script() { } # If you get errors like rate limit exceeded, you can run these tests -# with "AUTH_GITHUB=gitHubUserName:token" +# with "AUTH_GITHUB=token" # Follow this guide: https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token # to create an API token, and give it access to public repositories. if [ -z "${AUTH_GITHUB:-}" ] diff --git a/test/snapshots/flags/github-auth-bad-argument.txt b/test/snapshots/flags/github-auth-bad-argument.txt index 153b9c1ac..c9e3882d2 100644 --- a/test/snapshots/flags/github-auth-bad-argument.txt +++ b/test/snapshots/flags/github-auth-bad-argument.txt @@ -9,5 +9,5 @@ Here is the documentation for this flag: Follow https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token to create an API token. The API token needs access to public repositories. Then use the flag like this: - --github-auth=my-user-name:abcdef01234567890 + --github-auth=github_pat_abcdef01234567890 diff --git a/turbo.json b/turbo.json index c617777ac..4bff2f30c 100644 --- a/turbo.json +++ b/turbo.json @@ -1,7 +1,7 @@ { "$schema": "https://turbo.build/schema.json", - "globalEnv": ["NO_COLOR", "LOCAL_ELM_REVIEW_SRC", "ELM_HOME"], - "globalPassThroughEnv": ["AUTH_GITHUB"], + "globalEnv": ["NO_COLOR", "LOCAL_ELM_REVIEW_SRC"], + "globalPassThroughEnv": ["AUTH_GITHUB", "ELM_HOME"], "tasks": { "elm-format": { "inputs": [ From 993a0edf0658e3953124314c1f399586fc7a9eac Mon Sep 17 00:00:00 2001 From: Eli <88557639+lishaduck@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:17:32 -0600 Subject: [PATCH 3/3] feat: enhance rate limit error * Don't tell authenticated users to log in. * Tell users when the rate limit expires. --- lib/remote-template.js | 37 +++++++++++++------ .../flags/github-auth-bad-argument.txt | 2 +- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/lib/remote-template.js b/lib/remote-template.js index 08eeaa731..2c56efbd9 100644 --- a/lib/remote-template.js +++ b/lib/remote-template.js @@ -197,21 +197,31 @@ ${error.message}` } } -/** @type {ErrorMessageInfo} */ -const rateLimitErrorMessage = { - title: 'GITHUB RATE LIMIT EXCEEDED', - message: `It looks like you exceeded the GitHub rate limit by using "--template" too many -times, this will likely last for 30 minutes. - +/** + * @param {boolean} hasPat + * @param {string} resetTime + * @returns {ErrorMessageInfo} + */ +function rateLimitErrorMessage(hasPat, resetTime) { + return { + title: 'GITHUB RATE LIMIT EXCEEDED', + message: `It looks like you exceeded the GitHub rate limit by using "--template" too many +times, this will likely last until ${resetTime}. +${ + hasPat + ? '' + : ` In the meantime, you can use \`--github-auth=your-api-token\`. -Follow this guide: https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token to create an API token, and give it access to public repositories. +Follow this guide: https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token to create an API token, and give it access to public repositories.` +} To avoid this problem and to make the review process faster, consider setting up elm-review in your project: elm-review init elm-review init --template ` -}; + }; +} /** * @param {string} repoName @@ -380,11 +390,14 @@ async function makeGitHubApiRequest(options, url, handleNotFound) { Debug.log(`# body:\n${JSON.stringify(error.response.body, null, 4)}`); if (error.name === 'HTTPError') { switch (error.response.statusCode) { + case 429: case 403: { - throw new ErrorMessage.CustomError( - rateLimitErrorMessage.title, - rateLimitErrorMessage.message - ); + const hasPat = options.gitHubPat !== undefined; + const rateLimitReset = error.response.headers['x-ratelimit-reset']; + const resetTime = new Date(rateLimitReset * 1000).toLocaleString(); + const {title, message} = rateLimitErrorMessage(hasPat, resetTime); + + throw new ErrorMessage.CustomError(title, message); } case 404: diff --git a/test/snapshots/flags/github-auth-bad-argument.txt b/test/snapshots/flags/github-auth-bad-argument.txt index c9e3882d2..16d09dd68 100644 --- a/test/snapshots/flags/github-auth-bad-argument.txt +++ b/test/snapshots/flags/github-auth-bad-argument.txt @@ -1,6 +1,6 @@ -- INVALID FLAG ARGUMENT ------------------------------------------------------- -The value bad passed to --github-auth is not a valid one. +The value :: passed to --github-auth is not a valid one. Here is the documentation for this flag: