Skip to content

Commit

Permalink
feat: using app instead of user token (#31)
Browse files Browse the repository at this point in the history
* feat: using app instead of user token
* style: lint fixes
* fix: error throwing improvement
  • Loading branch information
0xGorilla authored May 6, 2024
1 parent 5f80a6c commit 244636b
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 20 deletions.
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
GH_OWNER=
GH_TOKEN=
GH_INSTALLATION_ID=
GH_APP_ID=
GH_PRIVATE_KEY=
GH_REPO_NAME=
GH_USER_CREATOR=
GH_TEMPLATE=
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/health-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ jobs:

- name: Health check steps
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
GH_OWNER: ${{ vars.GH_OWNER }}
GH_USER_CREATOR: ${{ github.actor }}
GH_APP_ID: ${{ vars.GH_APP_ID }}
GH_INSTALLATION_ID: ${{ secrets.GH_INSTALLATION_ID }}
GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
GH_USER_CREATOR: ${{ github.actor }}
run: yarn health-check
6 changes: 4 additions & 2 deletions .github/workflows/repo-creation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ jobs:

- name: Create repo steps
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
GH_OWNER: ${{ vars.GH_OWNER }}
GH_APP_ID: ${{ vars.GH_APP_ID }}
GH_INSTALLATION_ID: ${{ secrets.GH_INSTALLATION_ID }}
GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
GH_REPO_NAME: ${{ github.event.inputs.repo_name }}
GH_USER_CREATOR: ${{ github.actor }}
GH_TEMPLATE: ${{ github.event.inputs.template }}
LINEAR_PROJECT_CODE: ${{ github.event.inputs.linear_project_code }}
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
run: yarn create-repo
6 changes: 4 additions & 2 deletions .github/workflows/repo-doctor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ jobs:

- name: Repo doctor steps
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
GH_OWNER: ${{ vars.GH_OWNER }}
GH_APP_ID: ${{ vars.GH_APP_ID }}
GH_INSTALLATION_ID: ${{ secrets.GH_INSTALLATION_ID }}
GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
GH_REPO_NAME: ${{ github.event.inputs.repo_name }}
GH_USER_CREATOR: ${{ github.actor }}
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
run: yarn repo-doctor
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
"dependencies": {
"axios": "1.2.1",
"dotenv": "16.0.3",
"jsonwebtoken": "9.0.2",
"lint-staged": "13.1.0",
"yaml": "2.2.0"
},
"devDependencies": {
"@commitlint/cli": "12.1.4",
"@commitlint/config-conventional": "12.1.4",
"@types/chai": "4.3.3",
"@types/jsonwebtoken": "9.0.6",
"@types/mocha": "10.0.0",
"@types/node": "18.11.3",
"chai": "4.3.6",
Expand Down
32 changes: 30 additions & 2 deletions src/api/github-api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios, { AxiosInstance, AxiosResponse } from 'axios';
import * as jwt from 'jsonwebtoken';
import {
GetRefResponse,
CreateRefPayload,
Expand Down Expand Up @@ -29,6 +30,34 @@ export class GithubApi {
this.axios.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;
}

static async initialize(appId: string, installationId: string, privateKey: string, expirationDurationInSeconds: number = 600) {
const jwt = this.generateJWT(appId, privateKey, expirationDurationInSeconds);
const accessToken = await this.getInstallationAccessToken(jwt, installationId);
return new GithubApi(accessToken);
}

private static generateJWT(appId: string, privateKey: string, expirationDurationInSeconds: number) {
const now = Math.floor(Date.now() / 1000);
const payload = {
iat: now,
exp: now + expirationDurationInSeconds,
iss: appId,
};
return jwt.sign(payload, privateKey, { algorithm: 'RS256' });
}

private static async getInstallationAccessToken(jwt: any, installationId: string) {
const url = `https://api.github.com/app/installations/${installationId}/access_tokens`;
const headers = {
Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${jwt}`,
'User-Agent': 'My-Github-App',
};

const response = await axios.post(url, {}, { headers });
return response.data.token; // This is your installation access token
}

async createRepo(owner: string, createRepoPayload: RepoPayload): Promise<RepoResponse> {
const { data } = await this.axios.post<RepoResponse>(`/orgs/${owner}/repos`, createRepoPayload);
return data;
Expand Down Expand Up @@ -94,8 +123,7 @@ export class GithubApi {

async addPrTemplate(owner: string, repo: string, projectCode: string): Promise<void> {
const file = '.github/pull_request_template.md';
const content: string = `# 🤖 Linear\nCloses ${projectCode}-XXX
`;
const content: string = `# 🤖 Linear\n\nCloses ${projectCode}-XXX\n`;
const b64Content: string = Buffer.from(content).toString('base64');
const body: object = {
message: 'Added PR template to Repo',
Expand Down
8 changes: 5 additions & 3 deletions src/create-repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { RepoCheckers } from './utils/repo-checkers';
import { RepoUtils } from './utils/repo-utils';

const createRepo = async () => {
const token = getEnvVariable('GH_TOKEN');
const githubApi = new GithubApi(token);
const appId = getEnvVariable('GH_APP_ID');
const installationId = getEnvVariable('GH_INSTALLATION_ID');
const privateKey = getEnvVariable('GH_APP_PRIVATE_KEY');
const githubApi = await GithubApi.initialize(appId, installationId, privateKey);
const owner = getEnvVariable('GH_OWNER');
const repoUtils = new RepoUtils(githubApi);
const repo = getEnvVariable('GH_REPO_NAME').replace(/ /g, '-');
Expand Down Expand Up @@ -47,11 +49,11 @@ const createRepo = async () => {
console.log(`Link to the repo https://github.com/${owner}/${repo}`);
notifyDiscord(discordWebhook, `Repo **${repo}** successfully created 🚀 \nLink to the repo https://github.com/${owner}/${repo}`);
} catch (err) {
console.error(err);
await notifyDiscord(
discordWebhook,
`Repo **${repo}** creation failed ❌ please check the detailed logs at: https://github.com/defi-wonderland/repo-creatooor/actions/workflows/repo-creation.yml`
);
throw err;
}
};

Expand Down
11 changes: 7 additions & 4 deletions src/repo-doctor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { RepoCheckers } from './utils/repo-checkers';
import { RepoUtils } from './utils/repo-utils';

(async () => {
const token = getEnvVariable('GH_TOKEN');
const githubApi = new GithubApi(token);
const appId = getEnvVariable('GH_APP_ID');
const installationId = getEnvVariable('GH_INSTALLATION_ID');
const privateKey = getEnvVariable('GH_APP_PRIVATE_KEY');
const githubApi = await GithubApi.initialize(appId, installationId, privateKey);
const owner = getEnvVariable('GH_OWNER');
const repoUtils = new RepoUtils(githubApi);
const repo = getEnvVariable('GH_REPO_NAME');
Expand Down Expand Up @@ -78,12 +80,13 @@ import { RepoUtils } from './utils/repo-utils';
console.info(message);
discordNotifications.push(message);
}

notifyDiscord(discordWebhook, discordNotifications.join('\n\n'));
} catch (err) {
console.error(err);
const message = `👨‍⚕️❌ Repo doctor failed to heal **${repo}**\nIt will need manual intervention, please check the detailed logs at: https://github.com/defi-wonderland/repo-creatooor/actions/workflows/repo-doctor.yml`;
console.info(message);
discordNotifications.push(message);
} finally {
notifyDiscord(discordWebhook, discordNotifications.join('\n\n'));
throw err;
}
})();
6 changes: 4 additions & 2 deletions src/repos-health-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ type RepoDiagnostic = {

(async () => {
const diagnoses: RepoDiagnostic[] = [];
const token = getEnvVariable('GH_TOKEN');
const githubApi = new GithubApi(token);
const appId = getEnvVariable('GH_APP_ID');
const installationId = getEnvVariable('GH_INSTALLATION_ID');
const privateKey = getEnvVariable('GH_APP_PRIVATE_KEY');
const githubApi = await GithubApi.initialize(appId, installationId, privateKey);
const owner = getEnvVariable('GH_OWNER');
const repoUtils = new RepoUtils(githubApi);
const allRepos = await repoUtils.listAllRepos(owner);
Expand Down
98 changes: 96 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,13 @@
resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==

"@types/[email protected]":
version "9.0.6"
resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz#d1af3544d99ad992fb6681bbe60676e06b032bd3"
integrity sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==
dependencies:
"@types/node" "*"

"@types/minimatch@*":
version "5.1.2"
resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz"
Expand Down Expand Up @@ -440,6 +447,11 @@ [email protected]:
resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz"
integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==

[email protected]:
version "1.0.1"
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==

buffer-from@^1.0.0, buffer-from@^1.1.0:
version "1.1.2"
resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz"
Expand Down Expand Up @@ -755,6 +767,13 @@ eastasianwidth@^0.2.0:
resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz"
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==

[email protected]:
version "1.0.11"
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
dependencies:
safe-buffer "^5.0.1"

emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
Expand Down Expand Up @@ -1181,6 +1200,39 @@ jsonparse@^1.2.0:
resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz"
integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==

[email protected]:
version "9.0.2"
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3"
integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==
dependencies:
jws "^3.2.2"
lodash.includes "^4.3.0"
lodash.isboolean "^3.0.3"
lodash.isinteger "^4.0.4"
lodash.isnumber "^3.0.3"
lodash.isplainobject "^4.0.6"
lodash.isstring "^4.0.1"
lodash.once "^4.0.0"
ms "^2.1.1"
semver "^7.5.4"

jwa@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==
dependencies:
buffer-equal-constant-time "1.0.1"
ecdsa-sig-formatter "1.0.11"
safe-buffer "^5.0.1"

jws@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==
dependencies:
jwa "^1.4.1"
safe-buffer "^5.0.1"

kind-of@^6.0.3:
version "6.0.3"
resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
Expand Down Expand Up @@ -1243,6 +1295,41 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"

lodash.includes@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==

lodash.isboolean@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==

lodash.isinteger@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==

lodash.isnumber@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"
integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==

lodash.isplainobject@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==

lodash.isstring@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==

lodash.once@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==

lodash@^4.17.15, lodash@^4.17.19:
version "4.17.21"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
Expand Down Expand Up @@ -1424,7 +1511,7 @@ [email protected]:
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==

[email protected]:
[email protected], ms@^2.1.1:
version "2.1.3"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
Expand Down Expand Up @@ -1732,7 +1819,7 @@ rxjs@^7.8.0:
dependencies:
tslib "^2.1.0"

safe-buffer@^5.1.0, safe-buffer@~5.2.0:
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
Expand All @@ -1756,6 +1843,13 @@ semver@^7.3.4:
dependencies:
lru-cache "^6.0.0"

semver@^7.5.4:
version "7.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d"
integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==
dependencies:
lru-cache "^6.0.0"

[email protected]:
version "6.0.0"
resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz"
Expand Down

0 comments on commit 244636b

Please sign in to comment.