@sentry/junior-github 0.162.0 → 0.163.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 +99 -5
- package/dist/sandbox-paths.d.ts +4 -0
- package/dist/workspace-prepare.d.ts +3 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -730,12 +730,28 @@ import {
|
|
|
730
730
|
pluginToolOutputSchema
|
|
731
731
|
} from "@sentry/junior-plugin-api";
|
|
732
732
|
import { z } from "zod";
|
|
733
|
-
|
|
733
|
+
|
|
734
|
+
// src/sandbox-paths.ts
|
|
735
|
+
var RESERVED_SANDBOX_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
736
|
+
".junior",
|
|
737
|
+
"data",
|
|
738
|
+
"skills"
|
|
739
|
+
]);
|
|
740
|
+
function isReservedSandboxDirectory(path) {
|
|
741
|
+
return RESERVED_SANDBOX_DIRECTORIES.has(path.toLowerCase());
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// src/tools/clone-repository.ts
|
|
734
745
|
var inputSchema = z.object({
|
|
735
746
|
repo: z.string().describe('Repository in "owner/name" format.'),
|
|
736
|
-
directory: z.string().regex(/^[A-Za-z0-9._-]
|
|
737
|
-
|
|
738
|
-
|
|
747
|
+
directory: z.string().regex(/^(?:[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*)$/).refine(
|
|
748
|
+
(value) => !value.split("/").some((part) => part === "." || part === ".."),
|
|
749
|
+
{
|
|
750
|
+
message: "Directory must be a relative path without . or .. segments."
|
|
751
|
+
}
|
|
752
|
+
).describe(
|
|
753
|
+
"Optional destination directory under the sandbox root. Defaults to repos/{name}."
|
|
754
|
+
).optional()
|
|
739
755
|
}).strict();
|
|
740
756
|
var cloneSchema = z.object({
|
|
741
757
|
path: z.string(),
|
|
@@ -753,7 +769,7 @@ function parseRepo(value) {
|
|
|
753
769
|
return { owner: parts[0], name: parts[1] };
|
|
754
770
|
}
|
|
755
771
|
function defaultDirectory(repoName) {
|
|
756
|
-
return
|
|
772
|
+
return `repos/${repoName}`;
|
|
757
773
|
}
|
|
758
774
|
function commandSignal(signal, timeoutMs) {
|
|
759
775
|
const timeout = AbortSignal.timeout(timeoutMs);
|
|
@@ -802,7 +818,27 @@ function createGitHubCloneRepositoryTool(ctx) {
|
|
|
802
818
|
async execute(input, options) {
|
|
803
819
|
const repo = parseRepo(input.repo);
|
|
804
820
|
const directory = input.directory ?? defaultDirectory(repo.name);
|
|
821
|
+
const rootSegment = directory.split("/")[0] ?? directory;
|
|
822
|
+
if (isReservedSandboxDirectory(rootSegment)) {
|
|
823
|
+
throw new PluginToolInputError(
|
|
824
|
+
`Directory conflicts with a reserved sandbox path: ${directory}`
|
|
825
|
+
);
|
|
826
|
+
}
|
|
805
827
|
const path = `${ctx.sandbox.root}/${directory}`;
|
|
828
|
+
const parentDirectory = directory.includes("/") ? directory.slice(0, directory.lastIndexOf("/")) : void 0;
|
|
829
|
+
if (parentDirectory) {
|
|
830
|
+
const mkdir = await ctx.sandbox.run({
|
|
831
|
+
cmd: "mkdir",
|
|
832
|
+
args: ["-p", "--", `${ctx.sandbox.root}/${parentDirectory}`],
|
|
833
|
+
cwd: ctx.sandbox.root,
|
|
834
|
+
signal: commandSignal(options.signal, 3e4)
|
|
835
|
+
});
|
|
836
|
+
if (mkdir.exitCode !== 0) {
|
|
837
|
+
throw new PluginToolInputError(
|
|
838
|
+
`Failed to create clone parent directory: ${parentDirectory}`
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
806
842
|
const exists = await ctx.sandbox.run({
|
|
807
843
|
cmd: "bash",
|
|
808
844
|
args: ["-c", `test -e "$1"`, "bash", path],
|
|
@@ -4911,6 +4947,63 @@ function linkifyGitHubReferences(text2) {
|
|
|
4911
4947
|
}).join("\n");
|
|
4912
4948
|
}
|
|
4913
4949
|
|
|
4950
|
+
// src/workspace-prepare.ts
|
|
4951
|
+
async function prepareWorkspace(ctx) {
|
|
4952
|
+
const repos = ctx.repos.map((entry) => {
|
|
4953
|
+
const [owner, name, ...rest] = entry.repo.split("/");
|
|
4954
|
+
if (!owner || !name || rest.length > 0) {
|
|
4955
|
+
throw new Error(`Invalid GitHub repository: ${entry.repo}`);
|
|
4956
|
+
}
|
|
4957
|
+
const segments = entry.path.split("/");
|
|
4958
|
+
if (segments.length === 0 || segments.some(
|
|
4959
|
+
(part) => !part || part === "." || part === ".." || !/^[A-Za-z0-9._-]+$/.test(part)
|
|
4960
|
+
) || isReservedSandboxDirectory(segments[0])) {
|
|
4961
|
+
throw new Error(`Invalid workspace checkout path: ${entry.path}`);
|
|
4962
|
+
}
|
|
4963
|
+
return { owner, name, path: entry.path, repo: entry.repo };
|
|
4964
|
+
});
|
|
4965
|
+
const paths = /* @__PURE__ */ new Set();
|
|
4966
|
+
for (const entry of repos) {
|
|
4967
|
+
const key = entry.path.toLowerCase();
|
|
4968
|
+
if (paths.has(key)) {
|
|
4969
|
+
throw new Error(`Workspace checkout path collision: ${entry.path}`);
|
|
4970
|
+
}
|
|
4971
|
+
paths.add(key);
|
|
4972
|
+
}
|
|
4973
|
+
for (const { owner, name, path, repo } of repos) {
|
|
4974
|
+
const parent = path.includes("/") ? path.slice(0, path.lastIndexOf("/")) : void 0;
|
|
4975
|
+
if (parent) {
|
|
4976
|
+
const mkdir = await ctx.sandbox.run({
|
|
4977
|
+
cmd: "mkdir",
|
|
4978
|
+
args: ["-p", "--", parent],
|
|
4979
|
+
cwd: ctx.sandbox.root
|
|
4980
|
+
});
|
|
4981
|
+
if (mkdir.exitCode !== 0) {
|
|
4982
|
+
throw new Error(
|
|
4983
|
+
`GitHub workspace checkout parent failed for ${repo}: ${mkdir.stderr.trim() || `exit ${mkdir.exitCode}`}`
|
|
4984
|
+
);
|
|
4985
|
+
}
|
|
4986
|
+
}
|
|
4987
|
+
const result = await ctx.sandbox.run({
|
|
4988
|
+
cmd: "git",
|
|
4989
|
+
args: [
|
|
4990
|
+
"clone",
|
|
4991
|
+
"--quiet",
|
|
4992
|
+
"--depth=1",
|
|
4993
|
+
"--",
|
|
4994
|
+
`https://github.com/${owner}/${name}.git`,
|
|
4995
|
+
path
|
|
4996
|
+
],
|
|
4997
|
+
cwd: ctx.sandbox.root
|
|
4998
|
+
});
|
|
4999
|
+
if (result.exitCode !== 0) {
|
|
5000
|
+
throw new Error(
|
|
5001
|
+
`GitHub workspace clone failed for ${repo}: ${result.stderr.trim() || `exit ${result.exitCode}`}`
|
|
5002
|
+
);
|
|
5003
|
+
}
|
|
5004
|
+
}
|
|
5005
|
+
}
|
|
5006
|
+
|
|
4914
5007
|
// src/plugin.ts
|
|
4915
5008
|
function githubSmartHttpAccess(upstreamUrl) {
|
|
4916
5009
|
const pathname = upstreamUrl.pathname.toLowerCase();
|
|
@@ -5453,6 +5546,7 @@ function githubPlugin(options = {}) {
|
|
|
5453
5546
|
tools(ctx) {
|
|
5454
5547
|
return createGitHubTools(ctx);
|
|
5455
5548
|
},
|
|
5549
|
+
workspacePrepare: prepareWorkspace,
|
|
5456
5550
|
async sandboxPrepare(ctx) {
|
|
5457
5551
|
const hooksPath = `${ctx.sandbox.juniorRoot}/git-hooks`;
|
|
5458
5552
|
await ctx.sandbox.writeFile({
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Sandbox root directories reserved for Junior runtime material. */
|
|
2
|
+
export declare const RESERVED_SANDBOX_DIRECTORIES: Set<string>;
|
|
3
|
+
/** True when a checkout path collides with a reserved sandbox root (case-insensitive). */
|
|
4
|
+
export declare function isReservedSandboxDirectory(path: string): boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior-github",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.163.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.163.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^25.9.1",
|