@sentry/junior-github 0.102.1 → 0.102.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SETUP.md +10 -10
- package/dist/index.d.ts +4 -3
- package/dist/index.js +14 -22
- package/dist/permissions.d.ts +1 -1
- package/package.json +2 -2
- package/skills/github-code/SKILL.md +9 -2
- package/skills/github-code/references/api-surface.md +2 -2
- package/skills/github-code/references/troubleshooting-workarounds.md +3 -2
- package/skills/github-issues/references/troubleshooting-workarounds.md +13 -12
package/SETUP.md
CHANGED
|
@@ -64,7 +64,7 @@ vercel env update GITHUB_APP_PRIVATE_KEY production --sensitive < ./github-app-p
|
|
|
64
64
|
|
|
65
65
|
Repeat for `preview` and `development` as needed. After env changes, redeploy so the new deployment picks up updated values.
|
|
66
66
|
|
|
67
|
-
### Optional permission
|
|
67
|
+
### Optional permission declaration
|
|
68
68
|
|
|
69
69
|
By default, `installation-read` grants read the app installation's current permission envelope once per process and scopes read-capable permissions down to `read` when requesting a token. To declare the GitHub App permission envelope in the plugin and avoid that installation lookup, pass `appPermissions` when registering the plugin:
|
|
70
70
|
|
|
@@ -81,11 +81,11 @@ githubPlugin({
|
|
|
81
81
|
});
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
Junior records these permissions as plugin capabilities.
|
|
84
|
+
Junior records these permissions as plugin capabilities. Installation-read token requests remain read-only by requesting read-capable configured permissions at `read` level and omitting GitHub permission fields that have no `read` value. Installation-write token requests intentionally omit the `permissions` field, so GitHub applies the complete permission envelope approved on the App installation. GitHub remains the source of truth for whether a permission name or level exists.
|
|
85
85
|
|
|
86
86
|
GitHub App user-to-server tokens do not use OAuth scopes as their permission model. Their effective access is limited by the GitHub App's installed permissions, the app installation's repository access, and the requesting user's own GitHub access. Repository-scoped installation tokens instead use the App permission envelope and installation repository access without borrowing the requesting user's authority. GitHub returns an empty `scope` value for user-to-server tokens, so Junior cannot verify granted scopes from the token response.
|
|
87
87
|
|
|
88
|
-
If you pass `additionalUserScopes`, Junior includes those values in the authorization URL and records the requested scope string as a local reauthorization contract. This does not expand or prove GitHub API permissions
|
|
88
|
+
If you pass `additionalUserScopes`, Junior includes those values in the authorization URL and records the requested scope string as a local reauthorization contract. This does not expand or prove GitHub API permissions. Configure provider-enforced access in the GitHub App settings; `appPermissions` only declares capabilities and controls read-token downscoping:
|
|
89
89
|
|
|
90
90
|
```ts
|
|
91
91
|
githubPlugin({
|
|
@@ -93,7 +93,7 @@ githubPlugin({
|
|
|
93
93
|
});
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
Use `additionalUserScopes` only when a human-identity integration flow requires specific GitHub OAuth scope parameters in the authorization URL. Do not rely on it to authorize Junior-owned repository or workflow writes — those use repository-scoped installation tokens and the
|
|
96
|
+
Use `additionalUserScopes` only when a human-identity integration flow requires specific GitHub OAuth scope parameters in the authorization URL. Do not rely on it to authorize Junior-owned repository or workflow writes — those use repository-scoped installation tokens and the permissions approved on the GitHub App installation.
|
|
97
97
|
|
|
98
98
|
## 3) Runtime behavior
|
|
99
99
|
|
|
@@ -128,12 +128,12 @@ new resources through the typed tools, for example
|
|
|
128
128
|
Use `gh` for the allowlisted lifecycle operations described by the skill.
|
|
129
129
|
|
|
130
130
|
`gh` supports either direct `GITHUB_TOKEN` (for local debugging) or sandbox-level header injection.
|
|
131
|
-
The plugin uses installation credentials for read-only GitHub traffic, workflow dispatches, allowlisted issue and pull request mutations, and Git smart-HTTP pushes. GitHub App permissions still need to cover the operation: actions for workflow dispatches, issues for issue edits/comments/labels, contents for pushes, pull requests for PR mutations, and workflows for workflow-file pushes.
|
|
131
|
+
The plugin uses installation credentials for read-only GitHub traffic, workflow dispatches, allowlisted issue and pull request mutations, and Git smart-HTTP pushes. The installed GitHub App permissions still need to cover the operation: actions for workflow dispatches, issues for issue edits/comments/labels, contents for pushes, pull requests for PR mutations, and workflows for workflow-file pushes.
|
|
132
132
|
|
|
133
133
|
Committing and pushing code uses more than one GitHub surface:
|
|
134
134
|
|
|
135
135
|
- Creating the local Git commit does not call GitHub. Junior sets the GitHub App bot as author and committer and credits resolvable human actors with `Co-Authored-By` trailers.
|
|
136
|
-
- Pushing a branch with Git smart HTTP (`git push`) uses the repository-scoped `installation-write` grant and requires
|
|
136
|
+
- Pushing a branch with Git smart HTTP (`git push`) uses the repository-scoped `installation-write` grant and requires the App installation to have `Contents: write`. Workflow-file changes also require the installation to have `Workflows: write`.
|
|
137
137
|
- The smart-HTTP classifier does not distinguish Junior-managed branches or independently detect force updates or ref deletion. Use GitHub branch protection and limit the App installation to repositories where Junior may push.
|
|
138
138
|
- REST Git database and ref writes are denied by the current write allowlist. Use Git smart HTTP (`git push`) for branch updates instead.
|
|
139
139
|
- Opening the PR after the branch exists is separate: `github_createPullRequest` needs pull-request write permission, but it should not create or push commits itself.
|
|
@@ -144,10 +144,10 @@ Repository scoping and the egress allowlist are the write boundaries. Credential
|
|
|
144
144
|
|
|
145
145
|
Be careful with mixed-surface PR commands. Use the allowlisted REST endpoints
|
|
146
146
|
rather than GraphQL-backed `gh pr` mutation commands. PR-native title, body,
|
|
147
|
-
base, state, ready-for-review, and requested-reviewer changes use
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
remain unsupported API operations.
|
|
147
|
+
base, state, ready-for-review, and requested-reviewer changes use pull request
|
|
148
|
+
endpoints. Comments, labels, and assignees use GitHub's issue endpoints. All
|
|
149
|
+
allowlisted bot writes share `installation-write`; merge, branch deletion, REST
|
|
150
|
+
ref mutation, and administration remain unsupported API operations.
|
|
151
151
|
|
|
152
152
|
For PR creation in automation, push explicitly and pass that branch as `head`:
|
|
153
153
|
|
package/dist/index.d.ts
CHANGED
|
@@ -12,11 +12,12 @@ export interface GitHubPluginOptions {
|
|
|
12
12
|
*/
|
|
13
13
|
additionalUserScopes?: string[];
|
|
14
14
|
/**
|
|
15
|
-
* GitHub App
|
|
15
|
+
* GitHub App permissions Junior should expose as capabilities and downscope
|
|
16
|
+
* to read for installation-read tokens.
|
|
16
17
|
*
|
|
17
18
|
* Keys may use GitHub permission names with underscores or hyphens. Junior
|
|
18
|
-
* records these as plugin capabilities
|
|
19
|
-
*
|
|
19
|
+
* records these as plugin capabilities. Installation-write tokens inherit
|
|
20
|
+
* the App installation's complete permission envelope.
|
|
20
21
|
* GitHub remains the source of truth for whether a permission exists.
|
|
21
22
|
*/
|
|
22
23
|
appPermissions?: GitHubAppPermissions;
|
package/dist/index.js
CHANGED
|
@@ -848,6 +848,7 @@ var USER_REFRESH_TIMEOUT_MS = 2e4;
|
|
|
848
848
|
var GITHUB_GRAPHQL_RESPONSE_BODY_LIMIT_BYTES = 64 * 1024;
|
|
849
849
|
var HTTP_READ_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
|
|
850
850
|
var USER_TOKEN_GRANTS = /* @__PURE__ */ new Set(["user-read", "user-write"]);
|
|
851
|
+
var CREATE_TOOL_ROUTING_GUIDANCE = "This is a Junior tool-routing denial, not a GitHub permission failure. Do not ask the user for GitHub permissions; retry with the required Junior tool.";
|
|
851
852
|
var USER_WRITE_REQUIREMENTS = [
|
|
852
853
|
"requesting GitHub user permission to perform this operation"
|
|
853
854
|
];
|
|
@@ -1572,17 +1573,16 @@ async function issueInstallationCredential(options) {
|
|
|
1572
1573
|
throw new GitHubPluginSetupError(`Invalid ${options.installationIdEnv}`);
|
|
1573
1574
|
}
|
|
1574
1575
|
const appJwt = createAppJwt(appId, options.privateKeyEnv);
|
|
1575
|
-
const
|
|
1576
|
+
const body = "repositories" in options ? { repositories: options.repositories } : {
|
|
1577
|
+
permissions: "permissions" in options ? options.permissions : await options.loadPermissions({ appJwt, installationId })
|
|
1578
|
+
};
|
|
1576
1579
|
const accessTokenResponse = await githubRequest(
|
|
1577
1580
|
"https://api.github.com",
|
|
1578
1581
|
`/app/installations/${installationId}/access_tokens`,
|
|
1579
1582
|
{
|
|
1580
1583
|
method: "POST",
|
|
1581
1584
|
token: appJwt,
|
|
1582
|
-
body
|
|
1583
|
-
...permissions ? { permissions } : {},
|
|
1584
|
-
...options.repositories ? { repositories: options.repositories } : {}
|
|
1585
|
-
}
|
|
1585
|
+
body
|
|
1586
1586
|
}
|
|
1587
1587
|
);
|
|
1588
1588
|
const parsedToken = parseInstallationTokenResponse(accessTokenResponse);
|
|
@@ -1865,7 +1865,7 @@ function assertGitHubWriteAllowed(input) {
|
|
|
1865
1865
|
input.bodyText
|
|
1866
1866
|
)) {
|
|
1867
1867
|
throw new EgressPolicyDenied(
|
|
1868
|
-
|
|
1868
|
+
`GitHub issue creation must use the github_createIssue tool so Junior can own idempotency and the conversation footer. ${CREATE_TOOL_ROUTING_GUIDANCE}`
|
|
1869
1869
|
);
|
|
1870
1870
|
}
|
|
1871
1871
|
if (isGitHubPullCreateRestRequest(input.method, input.upstreamUrl) || isGitHubPullCreateGraphqlMutation(
|
|
@@ -1874,21 +1874,17 @@ function assertGitHubWriteAllowed(input) {
|
|
|
1874
1874
|
input.bodyText
|
|
1875
1875
|
)) {
|
|
1876
1876
|
throw new EgressPolicyDenied(
|
|
1877
|
-
|
|
1877
|
+
`GitHub pull request creation must use the github_createPullRequest tool so Junior can own idempotency and the conversation footer. ${CREATE_TOOL_ROUTING_GUIDANCE}`
|
|
1878
1878
|
);
|
|
1879
1879
|
}
|
|
1880
1880
|
}
|
|
1881
|
-
function grantRequirements(reason) {
|
|
1882
|
-
return reason === "github.user-write" ? USER_WRITE_REQUIREMENTS : void 0;
|
|
1883
|
-
}
|
|
1884
1881
|
function grantForAccess(access, reason, name, leaseScope) {
|
|
1885
|
-
const requirements = grantRequirements(reason);
|
|
1886
1882
|
return {
|
|
1887
1883
|
name,
|
|
1888
1884
|
access,
|
|
1889
1885
|
...leaseScope ? { leaseScope } : {},
|
|
1890
1886
|
reason,
|
|
1891
|
-
...
|
|
1887
|
+
...reason === "github.user-write" ? { requirements: USER_WRITE_REQUIREMENTS } : {}
|
|
1892
1888
|
};
|
|
1893
1889
|
}
|
|
1894
1890
|
function repositoryLeaseScope(upstreamUrl) {
|
|
@@ -1971,10 +1967,10 @@ function githubPlugin(options = {}) {
|
|
|
1971
1967
|
const appIdEnv = options.appIdEnv ?? GITHUB_APP_ID_ENV;
|
|
1972
1968
|
const privateKeyEnv = options.privateKeyEnv ?? GITHUB_APP_PRIVATE_KEY_ENV;
|
|
1973
1969
|
const installationIdEnv = options.installationIdEnv ?? GITHUB_INSTALLATION_ID_ENV;
|
|
1974
|
-
const
|
|
1975
|
-
const
|
|
1970
|
+
const declaredAppPermissions = normalizePermissions(options.appPermissions);
|
|
1971
|
+
const declaredReadPermissions = declaredAppPermissions ? readGrantPermissions(declaredAppPermissions) : void 0;
|
|
1976
1972
|
const loadReadPermissions = createPermissionCache();
|
|
1977
|
-
const appCapabilities = permissionCapabilities(
|
|
1973
|
+
const appCapabilities = permissionCapabilities(declaredAppPermissions);
|
|
1978
1974
|
const userScopes = normalizeScopeList(options.additionalUserScopes);
|
|
1979
1975
|
const userScope = userScopes.length ? userScopes.join(" ") : void 0;
|
|
1980
1976
|
return defineJuniorPlugin({
|
|
@@ -2090,7 +2086,7 @@ function githubPlugin(options = {}) {
|
|
|
2090
2086
|
appIdEnv,
|
|
2091
2087
|
privateKeyEnv,
|
|
2092
2088
|
installationIdEnv,
|
|
2093
|
-
...
|
|
2089
|
+
...declaredReadPermissions ? { permissions: declaredReadPermissions } : { loadPermissions: loadReadPermissions }
|
|
2094
2090
|
});
|
|
2095
2091
|
}
|
|
2096
2092
|
if (ctx.grant.name === "installation-write") {
|
|
@@ -2101,12 +2097,8 @@ function githubPlugin(options = {}) {
|
|
|
2101
2097
|
appIdEnv,
|
|
2102
2098
|
privateKeyEnv,
|
|
2103
2099
|
installationIdEnv,
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
...appPermissions,
|
|
2107
|
-
metadata: "read"
|
|
2108
|
-
}
|
|
2109
|
-
} : {},
|
|
2100
|
+
// This repository-only variant cannot downscope the installed
|
|
2101
|
+
// App envelope with an operation-specific permission body.
|
|
2110
2102
|
repositories: [repository.name]
|
|
2111
2103
|
});
|
|
2112
2104
|
}
|
package/dist/permissions.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type GitHubAppPermissionLevel = "admin" | "read" | "write";
|
|
2
2
|
export type GitHubAppPermissions = Record<string, GitHubAppPermissionLevel>;
|
|
3
|
-
/** Validate configured GitHub App
|
|
3
|
+
/** Validate the configured GitHub App capability and read-token declaration. */
|
|
4
4
|
export declare function normalizePermissions(permissions: GitHubAppPermissions | undefined): GitHubAppPermissions | undefined;
|
|
5
5
|
/** Build the read-only installation-token permission body. */
|
|
6
6
|
export declare function readGrantPermissions(permissions: Record<string, unknown> | undefined): Record<string, "read">;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior-github",
|
|
3
|
-
"version": "0.102.
|
|
3
|
+
"version": "0.102.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@sinclair/typebox": "^0.34.49",
|
|
27
27
|
"zod": "^4.4.3",
|
|
28
|
-
"@sentry/junior-plugin-api": "0.102.
|
|
28
|
+
"@sentry/junior-plugin-api": "0.102.3"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^25.9.1",
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: github-code
|
|
3
|
-
description: Work with GitHub repositories, source code, branches, commits, pushes, pull requests, reviews, diffs, and
|
|
3
|
+
description: Work with GitHub repositories, source code, branches, commits, pushes, pull requests, reviews, diffs, CI runs, and GitHub App credentials for branch and PR workflows. Use for repo implementation tasks, source-code investigation, cloning/fetching, branch and push workflows, PR creation or updates, PR review feedback, GitHub credential or permission failures involving repositories, pushes, or PRs, and GitHub Actions checks. Prefer this skill for repository and code tasks even when the repo concerns Sentry products.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# GitHub Code Operations
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## Credential contract
|
|
9
|
+
|
|
10
|
+
- Supported App-owned GitHub operations require no user-managed credential. Junior automatically mints and injects a repository-scoped GitHub App `installation-write` credential.
|
|
11
|
+
- For a pull request from an existing branch, push the branch first, then call `github_createPullRequest`; both operations receive the automatic installation credential.
|
|
12
|
+
- Do not ask the user to authorize GitHub, provide a token, or grant Contents/Pull requests permissions before trying a supported operation.
|
|
13
|
+
- Request remediation only after a supported operation returns evidence of an upstream provider denial. A Junior tool-routing denial means retry with the required tool, not request permissions.
|
|
14
|
+
|
|
15
|
+
Use `gh` and `git` for repository checkout, source investigation, code changes, commits, and pull request inspection or mutation. Use Junior's `github_createPullRequest` tool instead of `gh pr create` for new pull requests.
|
|
9
16
|
|
|
10
17
|
## References
|
|
11
18
|
|
|
@@ -65,9 +65,9 @@ jr-rpc config set github.repo owner/repo
|
|
|
65
65
|
- Prefer `--json` output for machine-readable parsing where available.
|
|
66
66
|
- Pass extra `git clone` flags after `--` (e.g. `gh repo clone owner/repo -- --depth=1`).
|
|
67
67
|
- A local `git commit` does not call GitHub. Pushing that commit uses Junior's repository-scoped installation credential and requires `github.contents.write` on the target repo.
|
|
68
|
-
- If the commit changes workflow files under `.github/workflows`,
|
|
68
|
+
- If the commit changes workflow files under `.github/workflows`, the App installation needs Workflows write in addition to Contents write.
|
|
69
69
|
- Before `github_createPullRequest`, push the head branch explicitly and resolve the target repo's default branch for `base`. That push requires GitHub write access to the remote.
|
|
70
70
|
- Merge, fork creation, workflow reruns or cancellations, REST contents/Git database writes, and repository administration are outside the current write allowlist.
|
|
71
71
|
- If the explicit `git push` fails with 401/403 or another access/permission error, verify the repo context and retry once. If it still fails, load troubleshooting guidance and report the exact command failure.
|
|
72
|
-
- PR comments, labels, and assignees use GitHub's issue endpoints
|
|
72
|
+
- PR comments, labels, and assignees use GitHub's issue endpoints; use the `github-issues` REST guidance for those operations. All allowlisted bot writes share the same repository-scoped `installation-write` credential.
|
|
73
73
|
- Return actionable errors for access, permission, not-found, and validation failures.
|
|
@@ -13,9 +13,10 @@ Use this table to recover quickly while keeping operations deterministic.
|
|
|
13
13
|
| `junior-auth-required provider=github grant=user-write` | User-to-server OAuth is missing or stale for a human-identity operation. | Follow the private OAuth prompt; do not ask the user to paste or manage tokens manually. |
|
|
14
14
|
| `git push` fails with 401/403 or auth/permission output | Write permission is missing, app installation is too narrow, or remote is wrong. | Verify the remote and repo context, retry once, then confirm app permissions and installation scope if it still fails. |
|
|
15
15
|
| Bash result includes `permission_denied` with `source: "upstream"` | GitHub returned 403 after Junior injected the named grant. | Do not call this a Junior runtime block. Use the message, connected account, upstream target, grant requirements, accepted-permissions, and SSO fields to explain the GitHub denial. |
|
|
16
|
-
| 403
|
|
16
|
+
| 403 without `permission_denied` where `source: "upstream"` | Junior may have rejected an unsupported route before contacting GitHub. | Read the response body. Follow any required-tool instruction; do not ask for GitHub permissions unless the failure is confirmed upstream. |
|
|
17
17
|
| `gh auth status` shows `Token scopes: none` | Expected for GitHub App user-to-server tokens. | Do not treat this as read-only proof. Use the failed command, `permission_denied.acceptedPermissions`, and GitHub App permissions instead. |
|
|
18
|
-
| `github_createPullRequest`
|
|
18
|
+
| `github_createPullRequest` returns upstream 401/403 | The App installation or target repository does not permit the operation. | Use the structured upstream denial to verify installation scope and accepted permissions; do not request user OAuth for this bot-owned operation. |
|
|
19
|
+
| `github_createPullRequest` returns 422 for `head` | The head branch was not pushed or the explicit head ref is wrong. | Push the branch, then retry with explicit `repo`, `head`, and `base` values. |
|
|
19
20
|
| `github_createPullRequest` fails with 422 validation on `base` | The `base` branch does not exist in the target repo. | Resolve the default branch with `gh repo view owner/repo --json defaultBranchRef --jq .defaultBranchRef.name`, then retry with that value as `base`. |
|
|
20
21
|
| `git blame`, long log history, or old commits are missing after clone | Repo was cloned shallow by design. | Deepen incrementally with `git -C DIRECTORY fetch --depth=N origin`, or `git -C DIRECTORY fetch --unshallow` when full history is required. |
|
|
21
22
|
| `sandbox setup failed (dnf install gh failed ...)` | `gh` package not available from the plugin runtime dependency bootstrap. | Report the plugin runtime bootstrap failure; do not try to repair package installation from the skill workflow. |
|
|
@@ -2,18 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
Use this table to recover quickly while keeping operations deterministic.
|
|
4
4
|
|
|
5
|
-
| Symptom
|
|
6
|
-
|
|
|
7
|
-
| `unknown command "issue"` from `gh`
|
|
8
|
-
| `Missing required option --repo`
|
|
9
|
-
| Command affects or authenticates against the wrong repo
|
|
10
|
-
| `GraphQL: Could not resolve to a Repository`
|
|
11
|
-
| 401 Unauthorized
|
|
12
|
-
| `junior-auth-required provider=github grant=user-write`
|
|
13
|
-
| 403
|
|
14
|
-
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
5
|
+
| Symptom | Likely cause | Fix |
|
|
6
|
+
| ---------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| `unknown command "issue"` from `gh` | CLI version too old or wrong binary in the plugin runtime. | Verify `gh --version`; if it is unavailable or too old, report that the GitHub plugin runtime dependency is not available. |
|
|
8
|
+
| `Missing required option --repo` | Repo not passed and no default was resolved. | Resolve with `jr-rpc config get github.repo`; pass `--repo owner/repo` explicitly when missing. |
|
|
9
|
+
| Command affects or authenticates against the wrong repo | Stale `github.repo` default or authenticated command missing explicit repo. | Pass `--repo owner/repo` for the target repository, or update `github.repo` before retrying. |
|
|
10
|
+
| `GraphQL: Could not resolve to a Repository` | Repo slug is wrong or inaccessible. | Validate `owner/repo` and confirm app installation on target repository. |
|
|
11
|
+
| 401 Unauthorized | Issued GitHub credentials were rejected upstream. | Verify the target repo, then use the grant/auth signal to distinguish stale user OAuth from app installation or host env setup. |
|
|
12
|
+
| `junior-auth-required provider=github grant=user-write` | User-to-server OAuth is missing or stale for a human-identity operation. | Follow the private OAuth prompt; do not ask the user to paste or manage tokens manually. |
|
|
13
|
+
| 403 without `permission_denied` where `source: "upstream"` | Junior may have rejected an unsupported route before contacting GitHub. | Read the response body. Follow any required-tool instruction; do not ask for GitHub permissions unless the failure is confirmed upstream. |
|
|
14
|
+
| `permission_denied` with `source: "upstream"` | GitHub rejected the injected installation credential. | Verify the target, accepted permissions, and App installation scope; do not request user OAuth for a bot-owned issue operation. |
|
|
15
|
+
| 404 Not Found | Issue number or repo is wrong. | Validate repo + issue ID with `gh issue view NUMBER --repo owner/repo`. |
|
|
16
|
+
| Issue label mutation fails | Wrong REST payload or wrong repo context. | Use the allowlisted issue labels endpoint with an explicit `owner/repo` path and valid JSON input. |
|
|
17
|
+
| Comment command fails with empty body | JSON input is missing a non-empty `body`. | Ensure the REST comment payload contains a non-empty `body` before retrying. |
|
|
17
18
|
|
|
18
19
|
## Retry guidance
|
|
19
20
|
|