diff --git a/.env.example b/.env.example
index 6e94876..8f9d0f5 100644
--- a/.env.example
+++ b/.env.example
@@ -1 +1,5 @@
-GITHUB_PERSONAL_ACCESS_TOKEN=
+APP_ID=123456
+PRIVATE_KEY_PATH=/path/to/app.private-key.pem
+CLIENT_ID=SomeClientId123
+CLIENT_SECRET=secret
+WEBHOOK_SECRET=secret
diff --git a/README.md b/README.md
index eb63f45..ea8cadf 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,48 @@
Towtruck is an application to aid maintenence of dxw's repos.
It aims to make it easier to keep on top of which repos need updates applying.
+
+
+## Configuration
+
+Towtruck is set up as a [GitHub App](https://docs.github.com/en/apps).
+
+
+### GitHub App settings
+
+The first step is to register a new app as described [here](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-github-app):
+- For **9**, no callback URL is currently required, so this step can be skipped.
+- For **11**, no user authentication is currently required, so this step can be skipped.
+- Skip **12** as Towtruck does not use device flow authentication.
+- For **13** and **14**, there is no additional in-app setup performed by Towtruck, so these steps can be skipped.
+- Skip **15** as Towtruck does receive GitHub webhooks and should be configured to listen for them.
+- For **16**, the webhook URL should be configured to `https:///api/github/webhooks`.
+ Alternatively, for development, a [Smee.io](https://smee.io/) channel can be used.
+- For **17**, a strong, randomly-generated secret should be used.
+- For **18**, SSL verification should be used.
+- For **19**, see the **Permissions** section below for a list of required permissions.
+- For **20**, see the **Webhooks** section below for a list of required webhooks to listen to.
+- For **21**, **Any account** should be used in production when Towtruck is used to monitor multiple organisations.
+ Otherwise, **Only this account** should be used.
+
+Once the app is registered, it should be installed to an account to allow Towtruck to track it.
+GitHub have instructions to do this [here](https://docs.github.com/en/apps/using-github-apps/installing-your-own-github-app).
+
+
+#### Permissions
+
+Towtruck is still in early development so the exact set of needed permissions has not been finalised.
+
+
+#### Webhooks
+
+Towtruck is still in early development so the exact set of needed webhooks has not been finalised.
+
+
+### Environment variables
+
+In order for Towtruck to communicate with the GitHub API, it needs several pieces of information, configured through environment variables:
+- `APP_ID`: The unique numeric ID assigned to the GitHub App.
+- `PRIVATE_KEY_PATH`: The private key used to sign access token requests. Towtruck expects this to be an absolute path to a `.pem` file generated by GitHub in the app settings.
+- `CLIENT_ID`: A unique alphanumeric ID assigned to the GitHub App.
+- `CLIENT_SECRET`: A token used to authenticate API requests. These are generated by GitHub in the app settings.
+- `WEBHOOK_SECRET`: A user-defined secret used to authenticate GitHub to Towtruck for receiving webhooks. This must be exactly the same as it is entered in the app settings on GitHub.
diff --git a/index.js b/index.js
index 2340a0e..f896f05 100644
--- a/index.js
+++ b/index.js
@@ -1,35 +1,45 @@
import { createServer } from "http";
-import { Octokit } from "@octokit/rest";
import nunjucks from "nunjucks";
+import { OctokitApp } from "./octokitApp.js";
nunjucks.configure({
autoescape: true,
watch: true,
});
-const ACCESS_TOKEN = process.env.GITHUB_PERSONAL_ACCESS_TOKEN;
-
-const octokit = new Octokit({
- auth: ACCESS_TOKEN,
-});
-
-const httpServer = createServer(async (_, response) => {
- const repos = await getRepos({ org: "dxw" });
-
- const template = nunjucks.render("index.njk", {
- repos,
+const httpServer = createServer(async (request, response) => {
+ if (await OctokitApp.middleware(request, response)) return;
+
+ // Currently we only want to support single-account installations.
+ // There doesn't seem to be a neat way to get the installation ID from an account name,
+ // so we will use `eachInstallation` to loop (hopefully once) and just take the first (hopefully only)
+ // element from `installations` so that we can have more meaningful template names in Nunjucks.
+ //
+ // We can enforce this one-installation approach through GitHub by configuring the app to be
+ // "Only on this account" when registering the app.
+
+ const installations = [];
+ await OctokitApp.app.eachInstallation(async octokit => {
+ const name = octokit.installation.account.login;
+
+ const repos = await getReposForInstallation(octokit);
+
+ installations.push({
+ name,
+ repos,
+ });
});
+ const template = nunjucks.render("index.njk", installations[0]);
+
return response.end(template);
});
-const getRepos = async ({ org }) => {
+const getReposForInstallation = async ({ octokit, installation }) => {
return octokit
- .request(`GET /orgs/${org}/repos`, {
- org,
- })
+ .request(installation.repositories_url)
.then(({ data }) => {
- return data.map((repo) => ({
+ return data.repositories.map((repo) => ({
name: repo.name,
}));
})
diff --git a/index.njk b/index.njk
index 595dc8d..3d0c287 100644
--- a/index.njk
+++ b/index.njk
@@ -10,10 +10,9 @@
Towtruck
-
- dxw's repos
+ {{ name }}'s repos
diff --git a/octokitApp.js b/octokitApp.js
new file mode 100644
index 0000000..331985b
--- /dev/null
+++ b/octokitApp.js
@@ -0,0 +1,31 @@
+import { readFileSync } from "fs";
+import { App, createNodeMiddleware } from "@octokit/app";
+
+const APP_ID = process.env.APP_ID;
+const PRIVATE_KEY_PATH = process.env.PRIVATE_KEY_PATH;
+const CLIENT_ID = process.env.CLIENT_ID;
+const CLIENT_SECRET = process.env.CLIENT_SECRET;
+const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
+
+const privateKey = readFileSync(PRIVATE_KEY_PATH).toString();
+
+const app = new App({
+ appId: APP_ID,
+ privateKey,
+ oauth: {
+ clientId: CLIENT_ID,
+ clientSecret: CLIENT_SECRET,
+ },
+ webhooks: {
+ secret: WEBHOOK_SECRET,
+ },
+});
+
+// eslint-disable-next-line no-unused-vars
+app.webhooks.onAny(({ id, name, payload }) => {
+ console.log(name, "event received");
+});
+
+const middleware = createNodeMiddleware(app);
+
+export const OctokitApp = { app, middleware };
diff --git a/package-lock.json b/package-lock.json
index 9ff775b..199f2ad 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,8 @@
"version": "0.0.1",
"license": "MIT",
"dependencies": {
- "@octokit/rest": "^21.0.2"
+ "@octokit/app": "^15.1.0",
+ "nunjucks": "^3.2.4"
},
"devDependencies": {
"@eslint/js": "^9.9.1",
@@ -196,6 +197,90 @@
"node": ">= 8"
}
},
+ "node_modules/@octokit/app": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/@octokit/app/-/app-15.1.0.tgz",
+ "integrity": "sha512-TkBr7QgOmE6ORxvIAhDbZsqPkF7RSqTY4pLTtUQCvr6dTXqvi2fFo46q3h1lxlk/sGMQjqyZ0kEahkD/NyzOHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/auth-app": "^7.0.0",
+ "@octokit/auth-unauthenticated": "^6.0.0",
+ "@octokit/core": "^6.1.2",
+ "@octokit/oauth-app": "^7.0.0",
+ "@octokit/plugin-paginate-rest": "^11.0.0",
+ "@octokit/types": "^13.0.0",
+ "@octokit/webhooks": "^13.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/@octokit/auth-app": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-7.1.1.tgz",
+ "integrity": "sha512-kRAd6yelV9OgvlEJE88H0VLlQdZcag9UlLr7dV0YYP37X8PPDvhgiTy66QVhDXdyoT0AleFN2w/qXkPdrSzINg==",
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/auth-oauth-app": "^8.1.0",
+ "@octokit/auth-oauth-user": "^5.1.0",
+ "@octokit/request": "^9.1.1",
+ "@octokit/request-error": "^6.1.1",
+ "@octokit/types": "^13.4.1",
+ "lru-cache": "^10.0.0",
+ "universal-github-app-jwt": "^2.2.0",
+ "universal-user-agent": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/@octokit/auth-oauth-app": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-8.1.1.tgz",
+ "integrity": "sha512-5UtmxXAvU2wfcHIPPDWzVSAWXVJzG3NWsxb7zCFplCWEmMCArSZV0UQu5jw5goLQXbFyOr5onzEH37UJB3zQQg==",
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/auth-oauth-device": "^7.0.0",
+ "@octokit/auth-oauth-user": "^5.0.1",
+ "@octokit/request": "^9.0.0",
+ "@octokit/types": "^13.0.0",
+ "universal-user-agent": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/@octokit/auth-oauth-device": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-7.1.1.tgz",
+ "integrity": "sha512-HWl8lYueHonuyjrKKIup/1tiy0xcmQCdq5ikvMO1YwkNNkxb6DXfrPjrMYItNLyCP/o2H87WuijuE+SlBTT8eg==",
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/oauth-methods": "^5.0.0",
+ "@octokit/request": "^9.0.0",
+ "@octokit/types": "^13.0.0",
+ "universal-user-agent": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/@octokit/auth-oauth-user": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-5.1.1.tgz",
+ "integrity": "sha512-rRkMz0ErOppdvEfnemHJXgZ9vTPhBuC6yASeFaB7I2yLMd7QpjfrL1mnvRPlyKo+M6eeLxrKanXJ9Qte29SRsw==",
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/auth-oauth-device": "^7.0.1",
+ "@octokit/oauth-methods": "^5.0.0",
+ "@octokit/request": "^9.0.1",
+ "@octokit/types": "^13.0.0",
+ "universal-user-agent": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
"node_modules/@octokit/auth-token": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.1.tgz",
@@ -205,6 +290,19 @@
"node": ">= 18"
}
},
+ "node_modules/@octokit/auth-unauthenticated": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-unauthenticated/-/auth-unauthenticated-6.1.0.tgz",
+ "integrity": "sha512-zPSmfrUAcspZH/lOFQnVnvjQZsIvmfApQH6GzJrkIunDooU1Su2qt2FfMTSVPRp7WLTQyC20Kd55lF+mIYaohQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/request-error": "^6.0.1",
+ "@octokit/types": "^13.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
"node_modules/@octokit/core": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.2.tgz",
@@ -250,43 +348,65 @@
"node": ">= 18"
}
},
- "node_modules/@octokit/openapi-types": {
- "version": "22.2.0",
- "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz",
- "integrity": "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==",
- "license": "MIT"
- },
- "node_modules/@octokit/plugin-paginate-rest": {
- "version": "11.3.3",
- "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.3.tgz",
- "integrity": "sha512-o4WRoOJZlKqEEgj+i9CpcmnByvtzoUYC6I8PD2SA95M+BJ2x8h7oLcVOg9qcowWXBOdcTRsMZiwvM3EyLm9AfA==",
+ "node_modules/@octokit/oauth-app": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@octokit/oauth-app/-/oauth-app-7.1.3.tgz",
+ "integrity": "sha512-EHXbOpBkSGVVGF1W+NLMmsnSsJRkcrnVmDKt0TQYRBb6xWfWzoi9sBD4DIqZ8jGhOWO/V8t4fqFyJ4vDQDn9bg==",
"license": "MIT",
"dependencies": {
- "@octokit/types": "^13.5.0"
+ "@octokit/auth-oauth-app": "^8.0.0",
+ "@octokit/auth-oauth-user": "^5.0.1",
+ "@octokit/auth-unauthenticated": "^6.0.0-beta.1",
+ "@octokit/core": "^6.0.0",
+ "@octokit/oauth-authorization-url": "^7.0.0",
+ "@octokit/oauth-methods": "^5.0.0",
+ "@types/aws-lambda": "^8.10.83",
+ "universal-user-agent": "^7.0.0"
},
"engines": {
"node": ">= 18"
- },
- "peerDependencies": {
- "@octokit/core": ">=6"
}
},
- "node_modules/@octokit/plugin-request-log": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-5.3.1.tgz",
- "integrity": "sha512-n/lNeCtq+9ofhC15xzmJCNKP2BWTv8Ih2TTy+jatNCCq/gQP/V7rK3fjIfuz0pDWDALO/o/4QY4hyOF6TQQFUw==",
+ "node_modules/@octokit/oauth-authorization-url": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-7.1.1.tgz",
+ "integrity": "sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA==",
"license": "MIT",
"engines": {
"node": ">= 18"
+ }
+ },
+ "node_modules/@octokit/oauth-methods": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-5.1.2.tgz",
+ "integrity": "sha512-C5lglRD+sBlbrhCUTxgJAFjWgJlmTx5bQ7Ch0+2uqRjYv7Cfb5xpX4WuSC9UgQna3sqRGBL9EImX9PvTpMaQ7g==",
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/oauth-authorization-url": "^7.0.0",
+ "@octokit/request": "^9.1.0",
+ "@octokit/request-error": "^6.1.0",
+ "@octokit/types": "^13.0.0"
},
- "peerDependencies": {
- "@octokit/core": ">=6"
+ "engines": {
+ "node": ">= 18"
}
},
- "node_modules/@octokit/plugin-rest-endpoint-methods": {
- "version": "13.2.4",
- "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.2.4.tgz",
- "integrity": "sha512-gusyAVgTrPiuXOdfqOySMDztQHv6928PQ3E4dqVGEtOvRXAKRbJR4b1zQyniIT9waqaWk/UDaoJ2dyPr7Bk7Iw==",
+ "node_modules/@octokit/openapi-types": {
+ "version": "22.2.0",
+ "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz",
+ "integrity": "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==",
+ "license": "MIT"
+ },
+ "node_modules/@octokit/openapi-webhooks-types": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@octokit/openapi-webhooks-types/-/openapi-webhooks-types-8.3.0.tgz",
+ "integrity": "sha512-vKLsoR4xQxg4Z+6rU/F65ItTUz/EXbD+j/d4mlq2GW8TsA4Tc8Kdma2JTAAJ5hrKWUQzkR/Esn2fjsqiVRYaQg==",
+ "license": "MIT"
+ },
+ "node_modules/@octokit/plugin-paginate-rest": {
+ "version": "11.3.3",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.3.tgz",
+ "integrity": "sha512-o4WRoOJZlKqEEgj+i9CpcmnByvtzoUYC6I8PD2SA95M+BJ2x8h7oLcVOg9qcowWXBOdcTRsMZiwvM3EyLm9AfA==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^13.5.0"
@@ -325,30 +445,50 @@
"node": ">= 18"
}
},
- "node_modules/@octokit/rest": {
- "version": "21.0.2",
- "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-21.0.2.tgz",
- "integrity": "sha512-+CiLisCoyWmYicH25y1cDfCrv41kRSvTq6pPWtRroRJzhsCZWZyCqGyI8foJT5LmScADSwRAnr/xo+eewL04wQ==",
+ "node_modules/@octokit/types": {
+ "version": "13.5.0",
+ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.5.0.tgz",
+ "integrity": "sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==",
"license": "MIT",
"dependencies": {
- "@octokit/core": "^6.1.2",
- "@octokit/plugin-paginate-rest": "^11.0.0",
- "@octokit/plugin-request-log": "^5.3.1",
- "@octokit/plugin-rest-endpoint-methods": "^13.0.0"
+ "@octokit/openapi-types": "^22.2.0"
+ }
+ },
+ "node_modules/@octokit/webhooks": {
+ "version": "13.3.0",
+ "resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-13.3.0.tgz",
+ "integrity": "sha512-TUkJLtI163Bz5+JK0O+zDkQpn4gKwN+BovclUvCj6pI/6RXrFqQvUMRS2M+Rt8Rv0qR3wjoMoOPmpJKeOh0nBg==",
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/openapi-webhooks-types": "8.3.0",
+ "@octokit/request-error": "^6.0.1",
+ "@octokit/webhooks-methods": "^5.0.0"
},
"engines": {
"node": ">= 18"
}
},
- "node_modules/@octokit/types": {
- "version": "13.5.0",
- "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.5.0.tgz",
- "integrity": "sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==",
+ "node_modules/@octokit/webhooks-methods": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-5.1.0.tgz",
+ "integrity": "sha512-yFZa3UH11VIxYnnoOYCVoJ3q4ChuSOk2IVBBQ0O3xtKX4x9bmKb/1t+Mxixv2iUhzMdOl1qeWJqEhouXXzB3rQ==",
"license": "MIT",
- "dependencies": {
- "@octokit/openapi-types": "^22.2.0"
+ "engines": {
+ "node": ">= 18"
}
},
+ "node_modules/@types/aws-lambda": {
+ "version": "8.10.145",
+ "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.145.tgz",
+ "integrity": "sha512-dtByW6WiFk5W5Jfgz1VM+YPA21xMXTuSFoLYIDY0L44jDLLflVPtZkYuu3/YxpGcvjzKFBZLU+GyKjR0HOYtyw==",
+ "license": "MIT"
+ },
+ "node_modules/a-sync-waterfall": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
+ "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==",
+ "license": "MIT"
+ },
"node_modules/acorn": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
@@ -455,6 +595,19 @@
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==",
"license": "Apache-2.0"
},
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -1000,7 +1153,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -1010,7 +1163,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
@@ -1127,6 +1280,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "license": "ISC"
+ },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -1479,6 +1638,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/universal-github-app-jwt": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-2.2.0.tgz",
+ "integrity": "sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ==",
+ "license": "MIT"
+ },
"node_modules/universal-user-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
diff --git a/package.json b/package.json
index f9c3d0c..b2fc985 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,7 @@
"author": "dxw",
"license": "MIT",
"dependencies": {
- "@octokit/rest": "^21.0.2",
+ "@octokit/app": "^15.1.0",
"nunjucks": "^3.2.4"
},
"devDependencies": {