@sentry/junior-github 0.53.0 → 0.55.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/README.md CHANGED
@@ -8,4 +8,23 @@ Install it alongside `@sentry/junior`:
8
8
  pnpm add @sentry/junior @sentry/junior-github
9
9
  ```
10
10
 
11
+ Register the trusted plugin from app code:
12
+
13
+ ```ts
14
+ import { createApp } from "@sentry/junior";
15
+ import { githubPlugin } from "@sentry/junior-github";
16
+
17
+ const app = await createApp({
18
+ plugins: [
19
+ githubPlugin({
20
+ botNameEnv: "GITHUB_APP_BOT_NAME",
21
+ botEmailEnv: "GITHUB_APP_BOT_EMAIL",
22
+ }),
23
+ ],
24
+ });
25
+ ```
26
+
27
+ Also list `@sentry/junior-github` in `juniorNitro({ plugins: { packages: [...] } })`
28
+ so Nitro bundles the manifest and bundled GitHub skill.
29
+
11
30
  Full setup guide: https://junior.sentry.dev/extend/github-plugin/
package/SETUP.md CHANGED
@@ -14,6 +14,7 @@ In GitHub:
14
14
  - Contents: Read and write
15
15
  - Pull requests: Read and write
16
16
  - Actions: Read and write
17
+ - Workflows: Write
17
18
  - Metadata: Read
18
19
 
19
20
  4. Create the app and generate a private key.
package/index.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { JuniorPlugin } from "@sentry/junior-plugin-api";
2
+
3
+ export interface GitHubPluginOptions {
4
+ botEmailEnv?: string;
5
+ botNameEnv?: string;
6
+ }
7
+
8
+ /** Register trusted GitHub runtime hooks for commit attribution and package loading. */
9
+ export function githubPlugin(options?: GitHubPluginOptions): JuniorPlugin;
package/index.js ADDED
@@ -0,0 +1,150 @@
1
+ import { defineJuniorPlugin } from "@sentry/junior-plugin-api";
2
+
3
+ function readEnv(name) {
4
+ const value = process.env[name];
5
+ return typeof value === "string" && value ? value : undefined;
6
+ }
7
+
8
+ function cleanIdentityPart(value) {
9
+ return String(value ?? "")
10
+ .replaceAll("\n", " ")
11
+ .replaceAll("\r", " ")
12
+ .replace(/[<>]/g, "")
13
+ .trim();
14
+ }
15
+
16
+ function requesterName(requester) {
17
+ return (
18
+ cleanIdentityPart(requester?.fullName) ||
19
+ cleanIdentityPart(requester?.userName) ||
20
+ cleanIdentityPart(requester?.userId) ||
21
+ undefined
22
+ );
23
+ }
24
+
25
+ function requesterEmail(requester) {
26
+ const email = cleanIdentityPart(requester?.email);
27
+ return email && !/\s/.test(email) ? email : "noreply";
28
+ }
29
+
30
+ function isGitCommitCommand(command) {
31
+ return /(?:^|[\s;|&])git(?:\s+(?:-C\s+\S+|-c\s+\S+|--git-dir(?:=\S+|\s+\S+)|--work-tree(?:=\S+|\s+\S+)|--namespace(?:=\S+|\s+\S+)))*\s+commit(?:\s|$)/.test(
32
+ command,
33
+ );
34
+ }
35
+
36
+ function prepareCommitMsgHook() {
37
+ return `#!/usr/bin/env bash
38
+ set -eu
39
+
40
+ message_file="\${1:-}"
41
+ if [ -z "$message_file" ]; then
42
+ exit 1
43
+ fi
44
+
45
+ if [ -z "\${JUNIOR_GIT_AUTHOR_NAME:-}" ] || [ -z "\${JUNIOR_GIT_AUTHOR_EMAIL:-}" ]; then
46
+ echo "Junior GitHub plugin internal error: bot commit attribution was not injected by the host runtime. Do not set Git author env vars manually; report this configuration error." >&2
47
+ exit 1
48
+ fi
49
+
50
+ if [ "\${GIT_AUTHOR_NAME:-}" != "$JUNIOR_GIT_AUTHOR_NAME" ] || [ "\${GIT_AUTHOR_EMAIL:-}" != "$JUNIOR_GIT_AUTHOR_EMAIL" ]; then
51
+ echo "Junior GitHub plugin internal error: Git author was not set to the configured bot identity. Do not override Git author manually; report this configuration error." >&2
52
+ exit 1
53
+ fi
54
+
55
+ if [ -z "\${JUNIOR_GIT_COAUTHOR_NAME:-}" ] || [ -z "\${JUNIOR_GIT_COAUTHOR_EMAIL:-}" ]; then
56
+ echo "Junior GitHub plugin internal error: requester coauthor identity was not injected by the host runtime. Do not set coauthor env vars manually; report this configuration error." >&2
57
+ exit 1
58
+ fi
59
+
60
+ trailer="Co-authored-by: $JUNIOR_GIT_COAUTHOR_NAME <$JUNIOR_GIT_COAUTHOR_EMAIL>"
61
+ if grep -Fqx "$trailer" "$message_file"; then
62
+ exit 0
63
+ fi
64
+
65
+ printf '\\n%s\\n' "$trailer" >> "$message_file"
66
+ `;
67
+ }
68
+
69
+ async function configureGit(ctx, key, value) {
70
+ const result = await ctx.sandbox.run({
71
+ cmd: "git",
72
+ args: ["config", "--global", key, value],
73
+ });
74
+ if (result.exitCode !== 0) {
75
+ throw new Error(
76
+ `Failed to configure git ${key}: ${result.stderr || result.stdout}`,
77
+ );
78
+ }
79
+ }
80
+
81
+ /** Register trusted GitHub runtime hooks for commit attribution and package loading. */
82
+ export function githubPlugin(options = {}) {
83
+ const botNameEnv = options.botNameEnv ?? "GITHUB_APP_BOT_NAME";
84
+ const botEmailEnv = options.botEmailEnv ?? "GITHUB_APP_BOT_EMAIL";
85
+
86
+ return defineJuniorPlugin({
87
+ name: "github",
88
+ pluginConfig: {
89
+ packages: ["@sentry/junior-github"],
90
+ },
91
+ hooks: {
92
+ async sandboxPrepare(ctx) {
93
+ const hooksPath = `${ctx.sandbox.juniorRoot}/git-hooks`;
94
+ await ctx.sandbox.writeFile({
95
+ path: `${hooksPath}/prepare-commit-msg`,
96
+ mode: 0o755,
97
+ content: prepareCommitMsgHook(),
98
+ });
99
+ await Promise.all([
100
+ configureGit(ctx, "core.hooksPath", hooksPath),
101
+ configureGit(ctx, "commit.gpgsign", "false"),
102
+ configureGit(ctx, "credential.helper", ""),
103
+ configureGit(ctx, "http.emptyAuth", "true"),
104
+ ]);
105
+ },
106
+ beforeToolExecute(ctx) {
107
+ if (ctx.tool.name !== "bash") {
108
+ return;
109
+ }
110
+ const command =
111
+ typeof ctx.tool.input === "object" &&
112
+ ctx.tool.input &&
113
+ "command" in ctx.tool.input
114
+ ? String(ctx.tool.input.command ?? "")
115
+ : "";
116
+ const botName = readEnv(botNameEnv);
117
+ const botEmail = readEnv(botEmailEnv);
118
+ if ((!botName || !botEmail) && isGitCommitCommand(command)) {
119
+ ctx.decision.deny(
120
+ `Junior GitHub plugin is misconfigured: host env vars ${botNameEnv} and ${botEmailEnv} are missing. This is an internal deployment configuration error; do not set them in the sandbox.`,
121
+ );
122
+ return;
123
+ }
124
+ if (!botName || !botEmail) {
125
+ return;
126
+ }
127
+ const coauthorName = requesterName(ctx.requester);
128
+ if (!coauthorName && isGitCommitCommand(command)) {
129
+ ctx.decision.deny(
130
+ "Junior GitHub plugin could not determine requester identity for commit attribution. This is an internal request-context error; do not set coauthor env vars manually.",
131
+ );
132
+ return;
133
+ }
134
+ ctx.env.set("GIT_AUTHOR_NAME", botName);
135
+ ctx.env.set("GIT_AUTHOR_EMAIL", botEmail);
136
+ ctx.env.set("GIT_COMMITTER_NAME", botName);
137
+ ctx.env.set("GIT_COMMITTER_EMAIL", botEmail);
138
+ ctx.env.set("JUNIOR_GIT_AUTHOR_NAME", botName);
139
+ ctx.env.set("JUNIOR_GIT_AUTHOR_EMAIL", botEmail);
140
+ if (coauthorName) {
141
+ ctx.env.set("JUNIOR_GIT_COAUTHOR_NAME", coauthorName);
142
+ ctx.env.set(
143
+ "JUNIOR_GIT_COAUTHOR_EMAIL",
144
+ requesterEmail(ctx.requester),
145
+ );
146
+ }
147
+ },
148
+ },
149
+ });
150
+ }
package/package.json CHANGED
@@ -1,14 +1,30 @@
1
1
  {
2
2
  "name": "@sentry/junior-github",
3
- "version": "0.53.0",
3
+ "version": "0.55.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
8
  "type": "module",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/getsentry/junior.git",
12
+ "directory": "packages/junior-github"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "types": "./index.d.ts",
17
+ "default": "./index.js"
18
+ }
19
+ },
9
20
  "files": [
21
+ "index.d.ts",
22
+ "index.js",
10
23
  "plugin.yaml",
11
24
  "skills",
12
25
  "SETUP.md"
13
- ]
26
+ ],
27
+ "dependencies": {
28
+ "@sentry/junior-plugin-api": "0.55.0"
29
+ }
14
30
  }
package/plugin.yaml CHANGED
@@ -1,16 +1,6 @@
1
1
  name: github
2
2
  description: GitHub issue, pull request, and repository workflows via GitHub App
3
3
 
4
- capabilities:
5
- - actions.read
6
- - actions.write
7
- - issues.read
8
- - issues.write
9
- - contents.read
10
- - contents.write
11
- - pull-requests.read
12
- - pull-requests.write
13
-
14
4
  config-keys:
15
5
  - org
16
6
  - repo
@@ -10,10 +10,10 @@ Use `gh` and `git` for repository checkout, source investigation, code changes,
10
10
 
11
11
  ## References
12
12
 
13
- | Need | Load |
14
- | ---- | ---- |
15
- | Command syntax, permissions, config | [references/api-surface.md](references/api-surface.md) |
16
- | Failed commands, auth errors | [references/troubleshooting-workarounds.md](references/troubleshooting-workarounds.md) |
13
+ | Need | Load |
14
+ | ----------------------------------- | -------------------------------------------------------------------------------------- |
15
+ | Command syntax, permissions, config | [references/api-surface.md](references/api-surface.md) |
16
+ | Failed commands, auth errors | [references/troubleshooting-workarounds.md](references/troubleshooting-workarounds.md) |
17
17
 
18
18
  ## Core rules
19
19
 
@@ -102,17 +102,7 @@ Types: `feat`, `fix`, `ref`, `docs`, `test`, `build`, `ci`, `chore`. Imperative
102
102
 
103
103
  Body only when it helps reviewers understand _why_.
104
104
 
105
- Footer order: `Fixes`/`Refs` lines, then `Co-authored-by` trailers.
106
-
107
- #### On-behalf-of commits
108
-
109
- If the commit is authored by a bot and a human requested the work, add a trailer:
110
-
111
- ```
112
- Co-authored-by: Full Name <email>
113
- ```
114
-
115
- Resolve name and email from evidence — requester context, Slack profile (`slackUserLookup`), GitHub profile, or repo commit history. If email cannot be confirmed, use `Full Name <noreply>` and note the gap in the PR body.
105
+ Footer order: `Fixes`/`Refs` lines.
116
106
 
117
107
  ### 6. Create or update PR
118
108