@sentry/junior-github 0.157.0 → 0.159.0
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/dist/index.js +51 -76
- package/package.json +2 -2
- package/skills/github-code/SKILL.md +2 -0
package/dist/index.js
CHANGED
|
@@ -20,7 +20,8 @@ import {
|
|
|
20
20
|
// src/plugin.ts
|
|
21
21
|
import {
|
|
22
22
|
defineJuniorPlugin,
|
|
23
|
-
EgressPolicyDenied as EgressPolicyDenied2
|
|
23
|
+
EgressPolicyDenied as EgressPolicyDenied2,
|
|
24
|
+
enforceEgressPolicy
|
|
24
25
|
} from "@sentry/junior-plugin-api";
|
|
25
26
|
|
|
26
27
|
// src/permissions.ts
|
|
@@ -4638,6 +4639,36 @@ function shouldInspectGitHubGraphqlResponse(ctx) {
|
|
|
4638
4639
|
const contentType = ctx.response.headers.get("content-type");
|
|
4639
4640
|
return contentType ? /\bjson\b/i.test(contentType) : false;
|
|
4640
4641
|
}
|
|
4642
|
+
var GITHUB_BODY_WRITES = [
|
|
4643
|
+
{
|
|
4644
|
+
denialMessage: `GitHub issue creation must use the github_createIssue tool so Junior can own idempotency and the conversation footer. ${CREATE_TOOL_ROUTING_GUIDANCE}`,
|
|
4645
|
+
graphqlField: "createIssue",
|
|
4646
|
+
method: "POST",
|
|
4647
|
+
operation: "github.issue.create",
|
|
4648
|
+
restPath: /^\/repos\/[^/]+\/[^/]+\/issues$/
|
|
4649
|
+
},
|
|
4650
|
+
{
|
|
4651
|
+
denialMessage: `GitHub pull request creation must use the github_createPullRequest tool so Junior can own idempotency and the conversation footer. ${CREATE_TOOL_ROUTING_GUIDANCE}`,
|
|
4652
|
+
graphqlField: "createPullRequest",
|
|
4653
|
+
method: "POST",
|
|
4654
|
+
operation: "github.pull.create",
|
|
4655
|
+
restPath: /^\/repos\/[^/]+\/[^/]+\/pulls$/
|
|
4656
|
+
},
|
|
4657
|
+
{
|
|
4658
|
+
denialMessage: `GitHub issue updates must use the github_updateIssue tool so Junior can own requester attribution and the conversation footer. ${CREATE_TOOL_ROUTING_GUIDANCE}`,
|
|
4659
|
+
graphqlField: "updateIssue",
|
|
4660
|
+
method: "PATCH",
|
|
4661
|
+
operation: "github.issue.update",
|
|
4662
|
+
restPath: /^\/repos\/[^/]+\/[^/]+\/issues\/[^/]+$/
|
|
4663
|
+
},
|
|
4664
|
+
{
|
|
4665
|
+
denialMessage: `GitHub pull request updates must use the github_updatePullRequest tool so Junior can own requester attribution and the conversation footer. ${CREATE_TOOL_ROUTING_GUIDANCE}`,
|
|
4666
|
+
graphqlField: "updatePullRequest",
|
|
4667
|
+
method: "PATCH",
|
|
4668
|
+
operation: "github.pull.update",
|
|
4669
|
+
restPath: /^\/repos\/[^/]+\/[^/]+\/pulls\/[^/]+$/
|
|
4670
|
+
}
|
|
4671
|
+
];
|
|
4641
4672
|
function githubApiWriteGrantName(method, upstreamUrl) {
|
|
4642
4673
|
const pathname = upstreamUrl.pathname.toLowerCase();
|
|
4643
4674
|
if (!isGitHubApiUrl2(upstreamUrl)) {
|
|
@@ -4653,26 +4684,19 @@ function githubApiWriteGrantName(method, upstreamUrl) {
|
|
|
4653
4684
|
) || /^\/repos\/[^/]+\/[^/]+\/actions\/jobs\/[^/]+\/rerun$/.test(pathname))) {
|
|
4654
4685
|
return "installation-write";
|
|
4655
4686
|
}
|
|
4656
|
-
if (
|
|
4687
|
+
if (GITHUB_BODY_WRITES.some(
|
|
4688
|
+
(write) => write.method === method && write.restPath.test(pathname)
|
|
4689
|
+
)) {
|
|
4657
4690
|
return "installation-write";
|
|
4658
4691
|
}
|
|
4659
4692
|
if (method === "POST" && /^\/repos\/[^/]+\/[^/]+\/issues\/[^/]+\/comments$/.test(pathname)) {
|
|
4660
4693
|
return "installation-write";
|
|
4661
4694
|
}
|
|
4662
|
-
if (method === "PATCH" && /^\/repos\/[^/]+\/[^/]+\/issues\/[^/]+$/.test(pathname)) {
|
|
4663
|
-
return "installation-write";
|
|
4664
|
-
}
|
|
4665
4695
|
if ((method === "POST" || method === "DELETE") && /^\/repos\/[^/]+\/[^/]+\/issues\/[^/]+\/(labels|assignees)(?:\/[^/]+)?$/.test(
|
|
4666
4696
|
pathname
|
|
4667
4697
|
)) {
|
|
4668
4698
|
return "installation-write";
|
|
4669
4699
|
}
|
|
4670
|
-
if (method === "POST" && /^\/repos\/[^/]+\/[^/]+\/pulls$/.test(pathname)) {
|
|
4671
|
-
return "installation-write";
|
|
4672
|
-
}
|
|
4673
|
-
if (method === "PATCH" && /^\/repos\/[^/]+\/[^/]+\/pulls\/[^/]+$/.test(pathname)) {
|
|
4674
|
-
return "installation-write";
|
|
4675
|
-
}
|
|
4676
4700
|
if (method === "POST" && /^\/repos\/[^/]+\/[^/]+\/pulls\/[^/]+\/ready_for_review$/.test(pathname)) {
|
|
4677
4701
|
return "installation-write";
|
|
4678
4702
|
}
|
|
@@ -4694,17 +4718,6 @@ function githubApiWriteGrantName(method, upstreamUrl) {
|
|
|
4694
4718
|
}
|
|
4695
4719
|
return void 0;
|
|
4696
4720
|
}
|
|
4697
|
-
function isGitHubIssueCreateRestRequest(method, upstreamUrl) {
|
|
4698
|
-
return method === "POST" && isGitHubApiUrl2(upstreamUrl) && /^\/repos\/[^/]+\/[^/]+\/issues$/.test(upstreamUrl.pathname.toLowerCase());
|
|
4699
|
-
}
|
|
4700
|
-
function isGitHubPullCreateRestRequest(method, upstreamUrl) {
|
|
4701
|
-
return method === "POST" && isGitHubApiUrl2(upstreamUrl) && /^\/repos\/[^/]+\/[^/]+\/pulls$/.test(upstreamUrl.pathname.toLowerCase());
|
|
4702
|
-
}
|
|
4703
|
-
function isGitHubResourceUpdateRestRequest(method, upstreamUrl, resource) {
|
|
4704
|
-
return method === "PATCH" && isGitHubApiUrl2(upstreamUrl) && new RegExp(`^/repos/[^/]+/[^/]+/${resource}/[^/]+$`).test(
|
|
4705
|
-
upstreamUrl.pathname.toLowerCase()
|
|
4706
|
-
);
|
|
4707
|
-
}
|
|
4708
4721
|
function isGitHubGraphqlMutation(method, upstreamUrl, bodyText, field) {
|
|
4709
4722
|
if (method !== "POST" || !isGitHubGraphqlUrl(upstreamUrl)) return false;
|
|
4710
4723
|
const parsed = parseGitHubGraphqlRequest(bodyText);
|
|
@@ -4716,64 +4729,26 @@ function isGitHubGraphqlMutation(method, upstreamUrl, bodyText, field) {
|
|
|
4716
4729
|
`\\bmutation\\s+${escapeRegExp2(parsed.operationName)}\\b`
|
|
4717
4730
|
).test(parsed.normalized);
|
|
4718
4731
|
}
|
|
4719
|
-
function
|
|
4732
|
+
function applyGitHubEgressPolicy(input) {
|
|
4720
4733
|
assertGitHubPullRequestApprovalDenied({
|
|
4721
4734
|
...input.bodyText !== void 0 ? { bodyText: input.bodyText } : {},
|
|
4722
4735
|
method: input.method,
|
|
4723
4736
|
upstreamUrl: input.upstreamUrl
|
|
4724
4737
|
});
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
)
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
}
|
|
4739
|
-
if (isGitHubPullCreateRestRequest(input.method, input.upstreamUrl) || isGitHubGraphqlMutation(
|
|
4740
|
-
input.method,
|
|
4741
|
-
input.upstreamUrl,
|
|
4742
|
-
input.bodyText,
|
|
4743
|
-
"createPullRequest"
|
|
4744
|
-
)) {
|
|
4745
|
-
throw new EgressPolicyDenied2(
|
|
4746
|
-
`GitHub pull request creation must use the github_createPullRequest tool so Junior can own idempotency and the conversation footer. ${CREATE_TOOL_ROUTING_GUIDANCE}`
|
|
4747
|
-
);
|
|
4748
|
-
}
|
|
4749
|
-
if (isGitHubResourceUpdateRestRequest(
|
|
4750
|
-
input.method,
|
|
4751
|
-
input.upstreamUrl,
|
|
4752
|
-
"issues"
|
|
4753
|
-
) || isGitHubGraphqlMutation(
|
|
4754
|
-
input.method,
|
|
4755
|
-
input.upstreamUrl,
|
|
4756
|
-
input.bodyText,
|
|
4757
|
-
"updateIssue"
|
|
4758
|
-
)) {
|
|
4759
|
-
throw new EgressPolicyDenied2(
|
|
4760
|
-
`GitHub issue updates must use the github_updateIssue tool so Junior can own requester attribution and the conversation footer. ${CREATE_TOOL_ROUTING_GUIDANCE}`
|
|
4761
|
-
);
|
|
4762
|
-
}
|
|
4763
|
-
if (isGitHubResourceUpdateRestRequest(
|
|
4764
|
-
input.method,
|
|
4765
|
-
input.upstreamUrl,
|
|
4766
|
-
"pulls"
|
|
4767
|
-
) || isGitHubGraphqlMutation(
|
|
4768
|
-
input.method,
|
|
4769
|
-
input.upstreamUrl,
|
|
4770
|
-
input.bodyText,
|
|
4771
|
-
"updatePullRequest"
|
|
4772
|
-
)) {
|
|
4773
|
-
throw new EgressPolicyDenied2(
|
|
4774
|
-
`GitHub pull request updates must use the github_updatePullRequest tool so Junior can own requester attribution and the conversation footer. ${CREATE_TOOL_ROUTING_GUIDANCE}`
|
|
4775
|
-
);
|
|
4776
|
-
}
|
|
4738
|
+
const pathname = input.upstreamUrl.pathname.toLowerCase();
|
|
4739
|
+
const write = GITHUB_BODY_WRITES.find(
|
|
4740
|
+
(candidate) => candidate.method === input.method && isGitHubApiUrl2(input.upstreamUrl) && candidate.restPath.test(pathname) || isGitHubGraphqlMutation(
|
|
4741
|
+
input.method,
|
|
4742
|
+
input.upstreamUrl,
|
|
4743
|
+
input.bodyText,
|
|
4744
|
+
candidate.graphqlField
|
|
4745
|
+
)
|
|
4746
|
+
);
|
|
4747
|
+
if (!write) return;
|
|
4748
|
+
enforceEgressPolicy({
|
|
4749
|
+
allowed: input.operation === write.operation,
|
|
4750
|
+
denialMessage: write.denialMessage
|
|
4751
|
+
});
|
|
4777
4752
|
}
|
|
4778
4753
|
function grantForAccess(access, reason, name, leaseScope) {
|
|
4779
4754
|
return {
|
|
@@ -4796,7 +4771,7 @@ function repositoryLeaseScope(upstreamUrl) {
|
|
|
4796
4771
|
async function githubGrantForEgress(ctx) {
|
|
4797
4772
|
const method = ctx.request.method.toUpperCase();
|
|
4798
4773
|
const upstreamUrl = new URL(ctx.request.url);
|
|
4799
|
-
|
|
4774
|
+
applyGitHubEgressPolicy({
|
|
4800
4775
|
...ctx.request.bodyText !== void 0 ? { bodyText: ctx.request.bodyText } : {},
|
|
4801
4776
|
method,
|
|
4802
4777
|
...ctx.request.operation ? { operation: ctx.request.operation } : {},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior-github",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.159.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@sinclair/typebox": "^0.34.49",
|
|
32
32
|
"drizzle-orm": "^0.45.2",
|
|
33
33
|
"zod": "^4.4.3",
|
|
34
|
-
"@sentry/junior-plugin-api": "0.
|
|
34
|
+
"@sentry/junior-plugin-api": "0.159.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^25.9.1",
|
|
@@ -81,3 +81,5 @@ If PR creation or update is blocked, report the exact failed command/tool call a
|
|
|
81
81
|
When PR creation returns a subscribable resource hint, subscribe to suggested review/CI events. Report only actionable feedback addressed, build failures fixed, fully green/ready state, or merge.
|
|
82
82
|
|
|
83
83
|
Return: repo, branch, PR URL/number, checks and results, pre-existing failures, and anything not run with the reason.
|
|
84
|
+
|
|
85
|
+
When you mention a pull request in a user-facing reply, always include a direct link. Prefer the full PR URL or a Markdown link such as `[#123](https://github.com/owner/repo/pull/123)`. `owner/repo#number` is also fine. Do not leave bare `PR #123` text without a URL or repo.
|