Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2156e19368 | |||
| b24274086f | |||
| 14350b6aaa | |||
| 6cf7b5f22a | |||
| 22e6bc6b49 | |||
| 3b3f07c3d1 | |||
| 7b860611c2 | |||
| a84c82dc20 | |||
| 81e8c224df | |||
| 7434028a6d | |||
| 46f9f788b8 | |||
| 3c69395e16 | |||
| 55b8c24e8d | |||
| cbc2930e9b |
@@ -1,3 +1,4 @@
|
||||
.env
|
||||
coverage
|
||||
node_modules/
|
||||
.DS_Store
|
||||
@@ -195,6 +195,28 @@ jobs:
|
||||
body: "Hello, World!"
|
||||
```
|
||||
|
||||
### Create a token for an enterprise installation
|
||||
|
||||
```yaml
|
||||
on: [workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
hello-world:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@v2
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.APP_ID }}
|
||||
private-key: ${{ secrets.PRIVATE_KEY }}
|
||||
enterprise-slug: my-enterprise-slug
|
||||
- name: Call enterprise management REST API with gh
|
||||
run: |
|
||||
gh api /enterprises/my-enterprise-slug/apps/installable_organizations
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
```
|
||||
|
||||
### Create a token with specific permissions
|
||||
|
||||
> [!NOTE]
|
||||
@@ -335,6 +357,13 @@ steps:
|
||||
> [!NOTE]
|
||||
> If `owner` is set and `repositories` is empty, access will be scoped to all repositories in the provided repository owner's installation. If `owner` and `repositories` are empty, access will be scoped to only the current repository.
|
||||
|
||||
### `enterprise-slug`
|
||||
|
||||
**Optional:** The slug of the enterprise to generate a token for enterprise-level app installations.
|
||||
|
||||
> [!NOTE]
|
||||
> The `enterprise-slug` input is mutually exclusive with `owner` and `repositories`. GitHub Apps can be installed on enterprise accounts with permissions that let them call enterprise management APIs. Enterprise installations do not grant access to organization or repository resources.
|
||||
|
||||
### `permission-<permission name>`
|
||||
|
||||
**Optional:** The permissions to grant to the token. By default, the token inherits all of the installation's permissions. We recommend to explicitly list the permissions that are required for a use case. This follows GitHub's own recommendation to [control permissions of `GITHUB_TOKEN` in workflows](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token). The documentation also lists all available permissions, just prefix the permission key with `permission-` (e.g., `pull-requests` → `permission-pull-requests`).
|
||||
|
||||
@@ -17,6 +17,9 @@ inputs:
|
||||
repositories:
|
||||
description: "Comma or newline-separated list of repositories to install the GitHub App on (defaults to current repository if owner is unset)"
|
||||
required: false
|
||||
enterprise-slug:
|
||||
description: "Enterprise slug for enterprise-level app installations (cannot be used with 'owner' or 'repositories')"
|
||||
required: false
|
||||
skip-token-revoke:
|
||||
description: "If true, the token will not be revoked when the current job is complete"
|
||||
required: false
|
||||
|
||||
+98
-37
@@ -4,6 +4,7 @@ import pRetry from "p-retry";
|
||||
/**
|
||||
* @param {string} appId
|
||||
* @param {string} privateKey
|
||||
* @param {string} enterpriseSlug
|
||||
* @param {string} owner
|
||||
* @param {string[]} repositories
|
||||
* @param {undefined | Record<string, string>} permissions
|
||||
@@ -15,58 +16,70 @@ import pRetry from "p-retry";
|
||||
export async function main(
|
||||
appId,
|
||||
privateKey,
|
||||
enterpriseSlug,
|
||||
owner,
|
||||
repositories,
|
||||
permissions,
|
||||
core,
|
||||
createAppAuth,
|
||||
request,
|
||||
skipTokenRevoke
|
||||
skipTokenRevoke,
|
||||
|
||||
) {
|
||||
// Validate mutual exclusivity of enterprise-slug with owner/repositories
|
||||
if (enterpriseSlug && (owner || repositories.length > 0)) {
|
||||
throw new Error("Cannot use 'enterprise-slug' input with 'owner' or 'repositories' inputs");
|
||||
}
|
||||
|
||||
let parsedOwner = "";
|
||||
let parsedRepositoryNames = [];
|
||||
|
||||
// If neither owner nor repositories are set, default to current repository
|
||||
if (!owner && repositories.length === 0) {
|
||||
const [owner, repo] = String(process.env.GITHUB_REPOSITORY).split("/");
|
||||
parsedOwner = owner;
|
||||
parsedRepositoryNames = [repo];
|
||||
// Skip owner/repository parsing if enterprise-slug is set
|
||||
if (!enterpriseSlug) {
|
||||
// If neither owner nor repositories are set, default to current repository
|
||||
if (!owner && repositories.length === 0) {
|
||||
const [owner, repo] = String(process.env.GITHUB_REPOSITORY).split("/");
|
||||
parsedOwner = owner;
|
||||
parsedRepositoryNames = [repo];
|
||||
|
||||
core.info(
|
||||
`Inputs 'owner' and 'repositories' are not set. Creating token for this repository (${owner}/${repo}).`
|
||||
);
|
||||
}
|
||||
core.info(
|
||||
`Inputs 'owner' and 'repositories' are not set. Creating token for this repository (${owner}/${repo}).`
|
||||
);
|
||||
}
|
||||
|
||||
// If only an owner is set, default to all repositories from that owner
|
||||
if (owner && repositories.length === 0) {
|
||||
parsedOwner = owner;
|
||||
// If only an owner is set, default to all repositories from that owner
|
||||
if (owner && repositories.length === 0) {
|
||||
parsedOwner = owner;
|
||||
|
||||
core.info(
|
||||
`Input 'repositories' is not set. Creating token for all repositories owned by ${owner}.`
|
||||
);
|
||||
}
|
||||
core.info(
|
||||
`Input 'repositories' is not set. Creating token for all repositories owned by ${owner}.`
|
||||
);
|
||||
}
|
||||
|
||||
// If repositories are set, but no owner, default to `GITHUB_REPOSITORY_OWNER`
|
||||
if (!owner && repositories.length > 0) {
|
||||
parsedOwner = String(process.env.GITHUB_REPOSITORY_OWNER);
|
||||
parsedRepositoryNames = repositories;
|
||||
// If repositories are set, but no owner, default to `GITHUB_REPOSITORY_OWNER`
|
||||
if (!owner && repositories.length > 0) {
|
||||
parsedOwner = String(process.env.GITHUB_REPOSITORY_OWNER);
|
||||
parsedRepositoryNames = repositories;
|
||||
|
||||
core.info(
|
||||
`No 'owner' input provided. Using default owner '${parsedOwner}' to create token for the following repositories:${repositories
|
||||
.map((repo) => `\n- ${parsedOwner}/${repo}`)
|
||||
.join("")}`
|
||||
);
|
||||
}
|
||||
core.info(
|
||||
`No 'owner' input provided. Using default owner '${parsedOwner}' to create token for the following repositories:${repositories
|
||||
.map((repo) => `\n- ${parsedOwner}/${repo}`)
|
||||
.join("")}`
|
||||
);
|
||||
}
|
||||
|
||||
// If both owner and repositories are set, use those values
|
||||
if (owner && repositories.length > 0) {
|
||||
parsedOwner = owner;
|
||||
parsedRepositoryNames = repositories;
|
||||
// If both owner and repositories are set, use those values
|
||||
if (owner && repositories.length > 0) {
|
||||
parsedOwner = owner;
|
||||
parsedRepositoryNames = repositories;
|
||||
|
||||
core.info(
|
||||
`Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:
|
||||
core.info(
|
||||
`Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:
|
||||
${repositories.map((repo) => `\n- ${parsedOwner}/${repo}`).join("")}`
|
||||
);
|
||||
);
|
||||
}
|
||||
} else {
|
||||
core.info(`Creating enterprise installation token for enterprise "${enterpriseSlug}".`);
|
||||
}
|
||||
|
||||
const auth = createAppAuth({
|
||||
@@ -76,9 +89,22 @@ export async function main(
|
||||
});
|
||||
|
||||
let authentication, installationId, appSlug;
|
||||
// If at least one repository is set, get installation ID from that repository
|
||||
|
||||
if (parsedRepositoryNames.length > 0) {
|
||||
|
||||
// If enterprise-slug is set, get installation ID from the enterprise
|
||||
if (enterpriseSlug) {
|
||||
({ authentication, installationId, appSlug } = await pRetry(
|
||||
() => getTokenFromEnterprise(request, auth, enterpriseSlug, permissions),
|
||||
{
|
||||
shouldRetry: (error) => error.status >= 500,
|
||||
onFailedAttempt: (error) => {
|
||||
core.info(
|
||||
`Failed to create token for enterprise "${enterpriseSlug}" (attempt ${error.attemptNumber}): ${error.message}`
|
||||
);
|
||||
},
|
||||
retries: 3,
|
||||
}
|
||||
));
|
||||
} else if (parsedRepositoryNames.length > 0) {
|
||||
({ authentication, installationId, appSlug } = await pRetry(
|
||||
() =>
|
||||
getTokenFromRepository(
|
||||
@@ -181,3 +207,38 @@ async function getTokenFromRepository(
|
||||
|
||||
return { authentication, installationId, appSlug };
|
||||
}
|
||||
|
||||
async function getTokenFromEnterprise(request, auth, enterpriseSlug, permissions) {
|
||||
// Get all installations and find the enterprise one
|
||||
// https://docs.github.com/rest/apps/apps#list-installations-for-the-authenticated-app
|
||||
// Note: Currently we do not have a way to get the installation for an enterprise directly,
|
||||
// so as a workaround we need to list all installations and filter for the enterprise one.
|
||||
const response = await request("GET /app/installations", {
|
||||
request: {
|
||||
hook: auth.hook,
|
||||
},
|
||||
});
|
||||
|
||||
// Find the enterprise installation
|
||||
const enterpriseInstallation = response.data.find(
|
||||
installation => installation.target_type === "Enterprise" &&
|
||||
installation.account?.slug === enterpriseSlug
|
||||
);
|
||||
|
||||
/* c8 ignore next 3 */
|
||||
if (!enterpriseInstallation) {
|
||||
throw new Error(`No enterprise installation found matching the name ${enterpriseSlug}. Available installations: ${response.data.map(i => `${i.target_type}:${i.account?.login || 'N/A'}`).join(', ')}`);
|
||||
}
|
||||
|
||||
// Get token for the enterprise installation
|
||||
const authentication = await auth({
|
||||
type: "installation",
|
||||
installationId: enterpriseInstallation.id,
|
||||
permissions,
|
||||
});
|
||||
|
||||
const installationId = enterpriseInstallation.id;
|
||||
const appSlug = enterpriseInstallation["app_slug"];
|
||||
|
||||
return { authentication, installationId, appSlug };
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ if (!process.env.GITHUB_REPOSITORY_OWNER) {
|
||||
|
||||
const appId = core.getInput("app-id");
|
||||
const privateKey = core.getInput("private-key");
|
||||
const enterpriseSlug = core.getInput("enterprise-slug");
|
||||
const owner = core.getInput("owner");
|
||||
const repositories = core
|
||||
.getInput("repositories")
|
||||
@@ -32,6 +33,7 @@ const permissions = getPermissionsFromInputs(process.env);
|
||||
export default main(
|
||||
appId,
|
||||
privateKey,
|
||||
enterpriseSlug,
|
||||
owner,
|
||||
repositories,
|
||||
permissions,
|
||||
@@ -40,7 +42,10 @@ export default main(
|
||||
request,
|
||||
skipTokenRevoke,
|
||||
).catch((error) => {
|
||||
/* c8 ignore next 3 */
|
||||
/* c8 ignore next 5 */
|
||||
console.error(error);
|
||||
core.setFailed(error.message);
|
||||
// Don't set failed in test mode (when GITHUB_OUTPUT is undefined)
|
||||
if (process.env.GITHUB_OUTPUT !== undefined) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { test } from "./main.js";
|
||||
|
||||
|
||||
// Verify `main` handles when no enterprise installation is found.
|
||||
await test((mockPool) => {
|
||||
delete process.env.INPUT_OWNER;
|
||||
delete process.env.INPUT_REPOSITORIES;
|
||||
process.env["INPUT_ENTERPRISE-SLUG"] = "test-enterprise";
|
||||
|
||||
|
||||
// Mock the /app/installations endpoint to return only non-enterprise installations
|
||||
mockPool
|
||||
.intercept({
|
||||
path: "/app/installations",
|
||||
method: "GET",
|
||||
headers: {
|
||||
accept: "application/vnd.github.v3+json",
|
||||
"user-agent": "actions/create-github-app-token",
|
||||
// Intentionally omitting the `authorization` header, since JWT creation is not idempotent.
|
||||
},
|
||||
})
|
||||
.reply(
|
||||
200,
|
||||
[
|
||||
{
|
||||
id: "111111",
|
||||
app_slug: "github-actions",
|
||||
target_type: "Organization",
|
||||
account: { login: "some-org" }
|
||||
},
|
||||
{
|
||||
id: "222222",
|
||||
app_slug: "github-actions",
|
||||
target_type: "User",
|
||||
account: { login: "some-user" }
|
||||
}
|
||||
],
|
||||
{ headers: { "content-type": "application/json" } }
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
import { DEFAULT_ENV } from "./main.js";
|
||||
|
||||
// Verify `main` exits with an error when `enterprise-slug` is used with both `owner` and `repositories` inputs.
|
||||
try {
|
||||
// Set up environment with enterprise-slug, owner, and repositories all set
|
||||
for (const [key, value] of Object.entries(DEFAULT_ENV)) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
process.env["INPUT_ENTERPRISE-SLUG"] = "test-enterprise";
|
||||
process.env.INPUT_OWNER = "test-owner";
|
||||
process.env.INPUT_REPOSITORIES = "repo1,repo2";
|
||||
|
||||
await import("../main.js");
|
||||
} catch (error) {
|
||||
console.error(error.message);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { DEFAULT_ENV } from "./main.js";
|
||||
|
||||
// Verify `main` exits with an error when `enterprise-slug` is used with `owner` input.
|
||||
try {
|
||||
// Set up environment with enterprise-slug and owner set
|
||||
for (const [key, value] of Object.entries(DEFAULT_ENV)) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
process.env["INPUT_ENTERPRISE-SLUG"] = "test-enterprise";
|
||||
process.env.INPUT_OWNER = "test-owner";
|
||||
|
||||
await import("../main.js");
|
||||
} catch (error) {
|
||||
console.error(error.message);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { DEFAULT_ENV } from "./main.js";
|
||||
|
||||
// Verify `main` exits with an error when `enterprise-slug` is used with `repositories` input.
|
||||
try {
|
||||
// Set up environment with enterprise-slug and repositories set
|
||||
for (const [key, value] of Object.entries(DEFAULT_ENV)) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
process.env["INPUT_ENTERPRISE-SLUG"] = "test-enterprise";
|
||||
process.env.INPUT_REPOSITORIES = "repo1,repo2";
|
||||
|
||||
await import("../main.js");
|
||||
} catch (error) {
|
||||
console.error(error.message);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { test } from "./main.js";
|
||||
|
||||
// Verify `main` successfully obtains a token when only the `enterprise-slug` input is set.
|
||||
await test((mockPool) => {
|
||||
process.env["INPUT_ENTERPRISE-SLUG"] = "test-enterprise";
|
||||
delete process.env.INPUT_OWNER;
|
||||
delete process.env.INPUT_REPOSITORIES;
|
||||
|
||||
// Mock the /app/installations endpoint to return an enterprise installation
|
||||
const mockInstallationId = "123456";
|
||||
const mockAppSlug = "github-actions";
|
||||
mockPool
|
||||
.intercept({
|
||||
path: "/app/installations",
|
||||
method: "GET",
|
||||
headers: {
|
||||
accept: "application/vnd.github.v3+json",
|
||||
"user-agent": "actions/create-github-app-token",
|
||||
// Intentionally omitting the `authorization` header, since JWT creation is not idempotent.
|
||||
},
|
||||
})
|
||||
.reply(
|
||||
200,
|
||||
[
|
||||
{
|
||||
id: mockInstallationId,
|
||||
app_slug: mockAppSlug,
|
||||
target_type: "Enterprise",
|
||||
account: { login: "test-enterprise", slug: "test-enterprise" }
|
||||
}
|
||||
],
|
||||
{ headers: { "content-type": "application/json" } }
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
import { test } from "./main.js";
|
||||
|
||||
// Verify `main` successfully generates enterprise token with basic functionality.
|
||||
await test((mockPool) => {
|
||||
process.env["INPUT_ENTERPRISE-SLUG"] = "test-enterprise";
|
||||
delete process.env.INPUT_OWNER;
|
||||
delete process.env.INPUT_REPOSITORIES;
|
||||
|
||||
// Mock the /app/installations endpoint to return an enterprise installation
|
||||
const mockInstallationId = "123456";
|
||||
const mockAppSlug = "github-actions";
|
||||
mockPool
|
||||
.intercept({
|
||||
path: "/app/installations",
|
||||
method: "GET",
|
||||
headers: {
|
||||
accept: "application/vnd.github.v3+json",
|
||||
"user-agent": "actions/create-github-app-token",
|
||||
// Intentionally omitting the `authorization` header, since JWT creation is not idempotent.
|
||||
},
|
||||
})
|
||||
.reply(
|
||||
200,
|
||||
[
|
||||
{
|
||||
id: mockInstallationId,
|
||||
app_slug: mockAppSlug,
|
||||
target_type: "Enterprise",
|
||||
account: { login: "test-enterprise", slug: "test-enterprise" }
|
||||
}
|
||||
],
|
||||
{ headers: { "content-type": "application/json" } }
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { test } from "./main.js";
|
||||
|
||||
// Verify `main` successfully generates enterprise token with specific permissions.
|
||||
await test((mockPool) => {
|
||||
process.env["INPUT_ENTERPRISE-SLUG"] = "test-enterprise";
|
||||
delete process.env.INPUT_OWNER;
|
||||
delete process.env.INPUT_REPOSITORIES;
|
||||
process.env["INPUT_PERMISSION-ENTERPRISE-ORGANIZATIONS"] = "read";
|
||||
process.env["INPUT_PERMISSION-ENTERPRISE-PEOPLE"] = "write";
|
||||
|
||||
// Mock the /app/installations endpoint to return an enterprise installation
|
||||
const mockInstallationId = "123456";
|
||||
const mockAppSlug = "github-actions";
|
||||
mockPool
|
||||
.intercept({
|
||||
path: "/app/installations",
|
||||
method: "GET",
|
||||
headers: {
|
||||
accept: "application/vnd.github.v3+json",
|
||||
"user-agent": "actions/create-github-app-token",
|
||||
// Intentionally omitting the `authorization` header, since JWT creation is not idempotent.
|
||||
},
|
||||
})
|
||||
.reply(
|
||||
200,
|
||||
[
|
||||
{
|
||||
id: mockInstallationId,
|
||||
app_slug: mockAppSlug,
|
||||
target_type: "Enterprise",
|
||||
account: { login: "test-enterprise", slug: "test-enterprise" }
|
||||
}
|
||||
],
|
||||
{ headers: { "content-type": "application/json" } }
|
||||
);
|
||||
});
|
||||
@@ -39,6 +39,139 @@ Generated by [AVA](https://avajs.dev).
|
||||
POST /api/v3/app/installations/123456/access_tokens␊
|
||||
{"repositories":["create-github-app-token"]}`
|
||||
|
||||
## main-enterprise-installation-not-found.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
`Error: No enterprise installation found matching the name test-enterprise. Available installations: Organization:some-org, User:some-user␊
|
||||
at getTokenFromEnterprise (file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/lib/main.js:230:11)␊
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)␊
|
||||
at async pRetry (file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/node_modules/p-retry/index.js:197:19)␊
|
||||
at async main (file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/lib/main.js:95:52)␊
|
||||
at async test (file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/tests/main.js:111:3)␊
|
||||
at async file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/tests/main-enterprise-installation-not-found.test.js:5:1`
|
||||
|
||||
> stdout
|
||||
|
||||
`Creating enterprise installation token for enterprise "test-enterprise".␊
|
||||
Failed to create token for enterprise "test-enterprise" (attempt 1): undefined␊
|
||||
--- REQUESTS ---␊
|
||||
GET /app/installations`
|
||||
|
||||
## main-enterprise-mutual-exclusivity-both.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
`Error: Cannot use 'enterprise-slug' input with 'owner' or 'repositories' inputs␊
|
||||
at main (file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/lib/main.js:31:11)␊
|
||||
at file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/main.js:33:16␊
|
||||
at ModuleJob.run (node:internal/modules/esm/module_job:430:25)␊
|
||||
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:639:26)␊
|
||||
at async file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/tests/main-enterprise-mutual-exclusivity-both.test.js:13:3`
|
||||
|
||||
> stdout
|
||||
|
||||
''
|
||||
|
||||
## main-enterprise-mutual-exclusivity-owner.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
`Error: Cannot use 'enterprise-slug' input with 'owner' or 'repositories' inputs␊
|
||||
at main (file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/lib/main.js:31:11)␊
|
||||
at file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/main.js:33:16␊
|
||||
at ModuleJob.run (node:internal/modules/esm/module_job:430:25)␊
|
||||
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:639:26)␊
|
||||
at async file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/tests/main-enterprise-mutual-exclusivity-owner.test.js:12:3`
|
||||
|
||||
> stdout
|
||||
|
||||
''
|
||||
|
||||
## main-enterprise-mutual-exclusivity-repositories.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
`Error: Cannot use 'enterprise-slug' input with 'owner' or 'repositories' inputs␊
|
||||
at main (file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/lib/main.js:31:11)␊
|
||||
at file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/main.js:33:16␊
|
||||
at ModuleJob.run (node:internal/modules/esm/module_job:430:25)␊
|
||||
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:639:26)␊
|
||||
at async file:///Users/parkerbxyz/.copilot/worktrees/create-github-app-token/pr-263/tests/main-enterprise-mutual-exclusivity-repositories.test.js:12:3`
|
||||
|
||||
> stdout
|
||||
|
||||
''
|
||||
|
||||
## main-enterprise-only-success.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
''
|
||||
|
||||
> stdout
|
||||
|
||||
`Creating enterprise installation token for enterprise "test-enterprise".␊
|
||||
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
|
||||
␊
|
||||
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
|
||||
␊
|
||||
::set-output name=installation-id::123456␊
|
||||
␊
|
||||
::set-output name=app-slug::github-actions␊
|
||||
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
|
||||
::save-state name=expiresAt::2016-07-11T22:14:10Z␊
|
||||
--- REQUESTS ---␊
|
||||
GET /app/installations␊
|
||||
POST /app/installations/123456/access_tokens␊
|
||||
null`
|
||||
|
||||
## main-enterprise-token-success.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
''
|
||||
|
||||
> stdout
|
||||
|
||||
`Creating enterprise installation token for enterprise "test-enterprise".␊
|
||||
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
|
||||
␊
|
||||
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
|
||||
␊
|
||||
::set-output name=installation-id::123456␊
|
||||
␊
|
||||
::set-output name=app-slug::github-actions␊
|
||||
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
|
||||
::save-state name=expiresAt::2016-07-11T22:14:10Z␊
|
||||
--- REQUESTS ---␊
|
||||
GET /app/installations␊
|
||||
POST /app/installations/123456/access_tokens␊
|
||||
null`
|
||||
|
||||
## main-enterprise-token-with-permissions.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
''
|
||||
|
||||
> stdout
|
||||
|
||||
`Creating enterprise installation token for enterprise "test-enterprise".␊
|
||||
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
|
||||
␊
|
||||
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
|
||||
␊
|
||||
::set-output name=installation-id::123456␊
|
||||
␊
|
||||
::set-output name=app-slug::github-actions␊
|
||||
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
|
||||
::save-state name=expiresAt::2016-07-11T22:14:10Z␊
|
||||
--- REQUESTS ---␊
|
||||
GET /app/installations␊
|
||||
POST /app/installations/123456/access_tokens␊
|
||||
{"permissions":{"enterprise_organizations":"read","enterprise_people":"write"}}`
|
||||
|
||||
## main-missing-owner.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user