@sentry/junior 0.50.0 → 0.52.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/app.js +313 -168
- package/dist/{chunk-AQ4RO2WA.js → chunk-KCOKQLBF.js} +1 -1
- package/dist/{chunk-UKR24HLJ.js → chunk-Q3FDONU7.js} +1 -0
- package/dist/{chunk-AYM42AN3.js → chunk-ZNFNY53B.js} +1 -1
- package/dist/cli/check.js +2 -2
- package/dist/cli/snapshot-warmup.js +2 -2
- package/dist/instrumentation.js +1 -0
- package/package.json +2 -2
package/dist/app.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
findSkillByName,
|
|
4
4
|
loadSkillsByName,
|
|
5
5
|
parseSkillInvocation
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ZNFNY53B.js";
|
|
7
7
|
import {
|
|
8
8
|
GEN_AI_PROVIDER_NAME,
|
|
9
9
|
MISSING_GATEWAY_CREDENTIALS_ERROR,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
runNonInteractiveCommand,
|
|
32
32
|
sandboxSkillDir,
|
|
33
33
|
sandboxSkillFile
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-KCOKQLBF.js";
|
|
35
35
|
import {
|
|
36
36
|
CredentialUnavailableError,
|
|
37
37
|
buildOAuthTokenRequest,
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
extractGenAiUsageAttributes,
|
|
43
43
|
extractGenAiUsageSummary,
|
|
44
44
|
getActiveTraceId,
|
|
45
|
+
getLogContextAttributes,
|
|
45
46
|
getPluginCapabilityProviders,
|
|
46
47
|
getPluginCatalogSignature,
|
|
47
48
|
getPluginDefinition,
|
|
@@ -69,7 +70,7 @@ import {
|
|
|
69
70
|
toOptionalString,
|
|
70
71
|
withContext,
|
|
71
72
|
withSpan
|
|
72
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-Q3FDONU7.js";
|
|
73
74
|
import {
|
|
74
75
|
sentry_exports
|
|
75
76
|
} from "./chunk-Z3YD6NHK.js";
|
|
@@ -6215,13 +6216,22 @@ function createSlackChannelListMessagesTool(context) {
|
|
|
6215
6216
|
}
|
|
6216
6217
|
throw error;
|
|
6217
6218
|
}
|
|
6218
|
-
|
|
6219
|
+
const summary = {
|
|
6219
6220
|
ok: true,
|
|
6220
6221
|
channel_id: targetChannelId,
|
|
6221
6222
|
count: result.messages.length,
|
|
6222
6223
|
next_cursor: result.nextCursor,
|
|
6223
6224
|
messages: result.messages
|
|
6224
6225
|
};
|
|
6226
|
+
return {
|
|
6227
|
+
content: [{ type: "text", text: JSON.stringify(summary) }],
|
|
6228
|
+
details: {
|
|
6229
|
+
ok: true,
|
|
6230
|
+
channel_id: targetChannelId,
|
|
6231
|
+
count: result.messages.length,
|
|
6232
|
+
...result.nextCursor ? { next_cursor: result.nextCursor } : {}
|
|
6233
|
+
}
|
|
6234
|
+
};
|
|
6225
6235
|
}
|
|
6226
6236
|
});
|
|
6227
6237
|
}
|
|
@@ -9044,87 +9054,135 @@ function resolveChannelCapabilities(channelId) {
|
|
|
9044
9054
|
};
|
|
9045
9055
|
}
|
|
9046
9056
|
|
|
9047
|
-
// src/chat/
|
|
9048
|
-
import
|
|
9049
|
-
|
|
9050
|
-
|
|
9051
|
-
function
|
|
9052
|
-
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
...manifest.credentials?.domains ?? [],
|
|
9057
|
-
...manifest.domains ?? []
|
|
9058
|
-
]);
|
|
9059
|
-
return [...domains].sort((left, right) => left.localeCompare(right));
|
|
9060
|
-
}
|
|
9061
|
-
function providerEntries() {
|
|
9062
|
-
return getPluginProviders().map((plugin) => ({
|
|
9063
|
-
provider: plugin.manifest.name,
|
|
9064
|
-
domains: manifestDomains(plugin.manifest)
|
|
9065
|
-
})).filter((entry) => entry.domains.length > 0).sort((left, right) => left.provider.localeCompare(right.provider));
|
|
9066
|
-
}
|
|
9067
|
-
function resolveSandboxEgressProviderForHost(host) {
|
|
9068
|
-
return providerEntries().find(
|
|
9069
|
-
(entry) => entry.domains.some((domain) => matchesSandboxEgressDomain(host, domain))
|
|
9070
|
-
)?.provider;
|
|
9071
|
-
}
|
|
9072
|
-
function sandboxProxyUrl() {
|
|
9073
|
-
const baseUrl = resolveBaseUrl();
|
|
9074
|
-
if (!baseUrl) {
|
|
9075
|
-
throw new Error(
|
|
9076
|
-
"Cannot determine base URL for sandbox credential egress (set JUNIOR_BASE_URL or deploy to Vercel)"
|
|
9077
|
-
);
|
|
9078
|
-
}
|
|
9079
|
-
return new URL("/", baseUrl).toString();
|
|
9080
|
-
}
|
|
9081
|
-
function buildSandboxEgressNetworkPolicy() {
|
|
9082
|
-
const allow = {
|
|
9083
|
-
"*": []
|
|
9057
|
+
// src/chat/pi/traced-stream.ts
|
|
9058
|
+
import {
|
|
9059
|
+
streamSimple
|
|
9060
|
+
} from "@mariozechner/pi-ai";
|
|
9061
|
+
function buildChatStartAttributes(model, context) {
|
|
9062
|
+
const attributes = {
|
|
9063
|
+
"gen_ai.operation.name": "chat",
|
|
9064
|
+
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
9065
|
+
"gen_ai.request.model": model.id
|
|
9084
9066
|
};
|
|
9085
|
-
const
|
|
9086
|
-
if (
|
|
9087
|
-
|
|
9067
|
+
const inputMessages = serializeGenAiAttribute(context.messages);
|
|
9068
|
+
if (inputMessages) {
|
|
9069
|
+
attributes["gen_ai.input.messages"] = inputMessages;
|
|
9088
9070
|
}
|
|
9089
|
-
|
|
9090
|
-
|
|
9091
|
-
|
|
9092
|
-
|
|
9071
|
+
if (context.systemPrompt) {
|
|
9072
|
+
const systemInstructions = serializeGenAiAttribute([
|
|
9073
|
+
{ type: "text", content: context.systemPrompt }
|
|
9074
|
+
]);
|
|
9075
|
+
if (systemInstructions) {
|
|
9076
|
+
attributes["gen_ai.system_instructions"] = systemInstructions;
|
|
9093
9077
|
}
|
|
9094
9078
|
}
|
|
9095
|
-
return
|
|
9079
|
+
return attributes;
|
|
9096
9080
|
}
|
|
9097
|
-
|
|
9098
|
-
const
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
Object.assign(env, resolvePluginCommandEnv(plugin.manifest));
|
|
9103
|
-
const credentials = plugin.manifest.credentials;
|
|
9104
|
-
if (credentials) {
|
|
9105
|
-
env[credentials.authTokenEnv] = resolveAuthTokenPlaceholder(credentials);
|
|
9106
|
-
}
|
|
9081
|
+
function buildChatEndAttributes(message) {
|
|
9082
|
+
const attributes = {};
|
|
9083
|
+
const outputMessages = serializeGenAiAttribute([message]);
|
|
9084
|
+
if (outputMessages) {
|
|
9085
|
+
attributes["gen_ai.output.messages"] = outputMessages;
|
|
9107
9086
|
}
|
|
9108
|
-
|
|
9087
|
+
Object.assign(attributes, extractGenAiUsageAttributes(message));
|
|
9088
|
+
if (message.stopReason) {
|
|
9089
|
+
attributes["gen_ai.response.finish_reasons"] = [message.stopReason];
|
|
9090
|
+
}
|
|
9091
|
+
if (message.model) {
|
|
9092
|
+
attributes["gen_ai.response.model"] = message.model;
|
|
9093
|
+
}
|
|
9094
|
+
return attributes;
|
|
9109
9095
|
}
|
|
9096
|
+
function createTracedStreamFn(base = streamSimple) {
|
|
9097
|
+
return async (model, context, options) => {
|
|
9098
|
+
const span = sentry_exports.startInactiveSpan({
|
|
9099
|
+
name: `chat ${model.id}`,
|
|
9100
|
+
op: "gen_ai.chat",
|
|
9101
|
+
attributes: {
|
|
9102
|
+
...getLogContextAttributes(),
|
|
9103
|
+
...buildChatStartAttributes(model, context)
|
|
9104
|
+
}
|
|
9105
|
+
});
|
|
9106
|
+
try {
|
|
9107
|
+
const stream = await sentry_exports.withActiveSpan(
|
|
9108
|
+
span,
|
|
9109
|
+
() => Promise.resolve(base(model, context, options))
|
|
9110
|
+
);
|
|
9111
|
+
stream.result().then(
|
|
9112
|
+
(finalMessage) => {
|
|
9113
|
+
try {
|
|
9114
|
+
for (const [key, value] of Object.entries(
|
|
9115
|
+
buildChatEndAttributes(finalMessage)
|
|
9116
|
+
)) {
|
|
9117
|
+
span.setAttribute(key, value);
|
|
9118
|
+
}
|
|
9119
|
+
} finally {
|
|
9120
|
+
span.end();
|
|
9121
|
+
}
|
|
9122
|
+
},
|
|
9123
|
+
() => {
|
|
9124
|
+
span.setStatus({ code: 2, message: "LLM stream failed" });
|
|
9125
|
+
span.end();
|
|
9126
|
+
}
|
|
9127
|
+
).catch(() => {
|
|
9128
|
+
});
|
|
9129
|
+
return stream;
|
|
9130
|
+
} catch (error) {
|
|
9131
|
+
span.setStatus({ code: 2, message: "LLM call failed" });
|
|
9132
|
+
span.end();
|
|
9133
|
+
throw error;
|
|
9134
|
+
}
|
|
9135
|
+
};
|
|
9136
|
+
}
|
|
9137
|
+
|
|
9138
|
+
// src/chat/sandbox/sandbox.ts
|
|
9139
|
+
import fs4 from "fs/promises";
|
|
9110
9140
|
|
|
9111
9141
|
// src/chat/sandbox/egress-session.ts
|
|
9112
|
-
import { randomUUID as randomUUID3 } from "crypto";
|
|
9113
|
-
var
|
|
9142
|
+
import { createHmac, randomUUID as randomUUID3, timingSafeEqual } from "crypto";
|
|
9143
|
+
var SANDBOX_EGRESS_PROXY_PATH = "/api/internal/sandbox-egress";
|
|
9144
|
+
var SANDBOX_EGRESS_TOKEN_VERSION = "v1";
|
|
9114
9145
|
var SANDBOX_EGRESS_LEASE_PREFIX = "sandbox-egress-lease";
|
|
9115
9146
|
var DEFAULT_SESSION_TTL_MS = 30 * 60 * 1e3;
|
|
9116
|
-
function
|
|
9117
|
-
return `${
|
|
9147
|
+
function leaseKey(provider, context) {
|
|
9148
|
+
return `${SANDBOX_EGRESS_LEASE_PREFIX}:${provider}:${context.requesterId}:${context.egressId}:${context.contextId}`;
|
|
9118
9149
|
}
|
|
9119
|
-
function
|
|
9120
|
-
|
|
9150
|
+
function getSandboxEgressSecret() {
|
|
9151
|
+
const explicit = process.env.JUNIOR_SANDBOX_EGRESS_SECRET?.trim();
|
|
9152
|
+
if (explicit) {
|
|
9153
|
+
return explicit;
|
|
9154
|
+
}
|
|
9155
|
+
const sharedInternal = process.env.JUNIOR_INTERNAL_RESUME_SECRET?.trim();
|
|
9156
|
+
if (sharedInternal) {
|
|
9157
|
+
return sharedInternal;
|
|
9158
|
+
}
|
|
9159
|
+
throw new Error(
|
|
9160
|
+
"Cannot determine sandbox egress secret (set JUNIOR_SANDBOX_EGRESS_SECRET or JUNIOR_INTERNAL_RESUME_SECRET)"
|
|
9161
|
+
);
|
|
9162
|
+
}
|
|
9163
|
+
function base64Url(input) {
|
|
9164
|
+
return Buffer.from(input, "utf8").toString("base64url");
|
|
9165
|
+
}
|
|
9166
|
+
function fromBase64Url(input) {
|
|
9167
|
+
return Buffer.from(input, "base64url").toString("utf8");
|
|
9168
|
+
}
|
|
9169
|
+
function signPayload(payload) {
|
|
9170
|
+
return createHmac("sha256", getSandboxEgressSecret()).update(payload).digest("base64url");
|
|
9171
|
+
}
|
|
9172
|
+
function timingSafeMatch(expected, actual) {
|
|
9173
|
+
const expectedBuffer = Buffer.from(expected);
|
|
9174
|
+
const actualBuffer = Buffer.from(actual);
|
|
9175
|
+
if (expectedBuffer.length !== actualBuffer.length) {
|
|
9176
|
+
return false;
|
|
9177
|
+
}
|
|
9178
|
+
return timingSafeEqual(expectedBuffer, actualBuffer);
|
|
9121
9179
|
}
|
|
9122
|
-
function
|
|
9180
|
+
function parseRequesterContext(value) {
|
|
9123
9181
|
if (!value || typeof value !== "object") {
|
|
9124
9182
|
return void 0;
|
|
9125
9183
|
}
|
|
9126
9184
|
const record = value;
|
|
9127
|
-
if (typeof record.requesterId !== "string" || typeof record.expiresAtMs !== "number" || !Number.isFinite(record.expiresAtMs) || typeof record.
|
|
9185
|
+
if (typeof record.requesterId !== "string" || !record.requesterId || typeof record.egressId !== "string" || !record.egressId || typeof record.expiresAtMs !== "number" || !Number.isFinite(record.expiresAtMs) || typeof record.contextId !== "string" || !record.contextId) {
|
|
9128
9186
|
return void 0;
|
|
9129
9187
|
}
|
|
9130
9188
|
if (record.expiresAtMs <= Date.now()) {
|
|
@@ -9132,8 +9190,9 @@ function parseSession(value) {
|
|
|
9132
9190
|
}
|
|
9133
9191
|
return {
|
|
9134
9192
|
requesterId: record.requesterId,
|
|
9193
|
+
egressId: record.egressId,
|
|
9135
9194
|
expiresAtMs: record.expiresAtMs,
|
|
9136
|
-
|
|
9195
|
+
contextId: record.contextId
|
|
9137
9196
|
};
|
|
9138
9197
|
}
|
|
9139
9198
|
function parseLease(value) {
|
|
@@ -9162,50 +9221,127 @@ function parseLease(value) {
|
|
|
9162
9221
|
headerTransforms
|
|
9163
9222
|
};
|
|
9164
9223
|
}
|
|
9165
|
-
|
|
9166
|
-
const state = getStateAdapter();
|
|
9167
|
-
await state.connect();
|
|
9224
|
+
function createSandboxEgressRequesterToken(input) {
|
|
9168
9225
|
const ttlMs = Math.max(1, input.ttlMs ?? DEFAULT_SESSION_TTL_MS);
|
|
9169
9226
|
const now = Date.now();
|
|
9170
|
-
const
|
|
9227
|
+
const context = {
|
|
9171
9228
|
requesterId: input.requesterId,
|
|
9229
|
+
egressId: input.egressId,
|
|
9172
9230
|
expiresAtMs: now + ttlMs,
|
|
9173
|
-
|
|
9231
|
+
contextId: randomUUID3()
|
|
9174
9232
|
};
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
9178
|
-
|
|
9179
|
-
await state.connect();
|
|
9180
|
-
await state.delete(sessionKey2(egressId));
|
|
9233
|
+
const payload = `${SANDBOX_EGRESS_TOKEN_VERSION}.${base64Url(
|
|
9234
|
+
JSON.stringify(context)
|
|
9235
|
+
)}`;
|
|
9236
|
+
return `${payload}.${signPayload(payload)}`;
|
|
9181
9237
|
}
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
|
|
9185
|
-
|
|
9238
|
+
function parseSandboxEgressRequesterToken(token) {
|
|
9239
|
+
if (!token) {
|
|
9240
|
+
return void 0;
|
|
9241
|
+
}
|
|
9242
|
+
const parts = token.split(".");
|
|
9243
|
+
if (parts.length !== 3 || parts[0] !== SANDBOX_EGRESS_TOKEN_VERSION) {
|
|
9244
|
+
return void 0;
|
|
9245
|
+
}
|
|
9246
|
+
const encodedSession = parts[1];
|
|
9247
|
+
const signature = parts[2];
|
|
9248
|
+
if (!encodedSession || !signature) {
|
|
9249
|
+
return void 0;
|
|
9250
|
+
}
|
|
9251
|
+
const payload = `${parts[0]}.${encodedSession}`;
|
|
9252
|
+
if (!timingSafeMatch(signPayload(payload), signature)) {
|
|
9253
|
+
return void 0;
|
|
9254
|
+
}
|
|
9255
|
+
try {
|
|
9256
|
+
return parseRequesterContext(JSON.parse(fromBase64Url(encodedSession)));
|
|
9257
|
+
} catch {
|
|
9258
|
+
return void 0;
|
|
9259
|
+
}
|
|
9186
9260
|
}
|
|
9187
|
-
async function setSandboxEgressCredentialLease(
|
|
9261
|
+
async function setSandboxEgressCredentialLease(context, lease) {
|
|
9188
9262
|
const leaseExpiresAtMs = Date.parse(lease.expiresAt);
|
|
9189
9263
|
if (!Number.isFinite(leaseExpiresAtMs) || leaseExpiresAtMs <= Date.now()) {
|
|
9190
9264
|
return;
|
|
9191
9265
|
}
|
|
9192
9266
|
const ttlMs = Math.max(
|
|
9193
9267
|
1,
|
|
9194
|
-
Math.min(leaseExpiresAtMs,
|
|
9268
|
+
Math.min(leaseExpiresAtMs, context.expiresAtMs) - Date.now()
|
|
9195
9269
|
);
|
|
9196
9270
|
const state = getStateAdapter();
|
|
9197
9271
|
await state.connect();
|
|
9198
|
-
await state.set(leaseKey(
|
|
9272
|
+
await state.set(leaseKey(lease.provider, context), lease, ttlMs);
|
|
9199
9273
|
}
|
|
9200
|
-
async function getSandboxEgressCredentialLease(
|
|
9274
|
+
async function getSandboxEgressCredentialLease(provider, context) {
|
|
9201
9275
|
const state = getStateAdapter();
|
|
9202
9276
|
await state.connect();
|
|
9203
|
-
return parseLease(await state.get(leaseKey(
|
|
9277
|
+
return parseLease(await state.get(leaseKey(provider, context)));
|
|
9204
9278
|
}
|
|
9205
|
-
async function clearSandboxEgressCredentialLease(
|
|
9279
|
+
async function clearSandboxEgressCredentialLease(provider, context) {
|
|
9206
9280
|
const state = getStateAdapter();
|
|
9207
9281
|
await state.connect();
|
|
9208
|
-
await state.delete(leaseKey(
|
|
9282
|
+
await state.delete(leaseKey(provider, context));
|
|
9283
|
+
}
|
|
9284
|
+
|
|
9285
|
+
// src/chat/sandbox/egress-policy.ts
|
|
9286
|
+
function matchesSandboxEgressDomain(host, domain) {
|
|
9287
|
+
return host.toLowerCase() === domain.toLowerCase();
|
|
9288
|
+
}
|
|
9289
|
+
function manifestDomains(manifest) {
|
|
9290
|
+
const domains = /* @__PURE__ */ new Set([
|
|
9291
|
+
...manifest.credentials?.domains ?? [],
|
|
9292
|
+
...manifest.domains ?? []
|
|
9293
|
+
]);
|
|
9294
|
+
return [...domains].sort((left, right) => left.localeCompare(right));
|
|
9295
|
+
}
|
|
9296
|
+
function providerEntries() {
|
|
9297
|
+
return getPluginProviders().map((plugin) => ({
|
|
9298
|
+
provider: plugin.manifest.name,
|
|
9299
|
+
domains: manifestDomains(plugin.manifest)
|
|
9300
|
+
})).filter((entry) => entry.domains.length > 0).sort((left, right) => left.provider.localeCompare(right.provider));
|
|
9301
|
+
}
|
|
9302
|
+
function resolveSandboxEgressProviderForHost(host) {
|
|
9303
|
+
return providerEntries().find(
|
|
9304
|
+
(entry) => entry.domains.some((domain) => matchesSandboxEgressDomain(host, domain))
|
|
9305
|
+
)?.provider;
|
|
9306
|
+
}
|
|
9307
|
+
function sandboxProxyUrl(requesterToken) {
|
|
9308
|
+
const baseUrl = resolveBaseUrl();
|
|
9309
|
+
if (!baseUrl) {
|
|
9310
|
+
throw new Error(
|
|
9311
|
+
"Cannot determine base URL for sandbox credential egress (set JUNIOR_BASE_URL or deploy to Vercel)"
|
|
9312
|
+
);
|
|
9313
|
+
}
|
|
9314
|
+
const path11 = requesterToken ? `${SANDBOX_EGRESS_PROXY_PATH}/${requesterToken}` : SANDBOX_EGRESS_PROXY_PATH;
|
|
9315
|
+
return new URL(path11, baseUrl).toString();
|
|
9316
|
+
}
|
|
9317
|
+
function buildSandboxEgressNetworkPolicy(input) {
|
|
9318
|
+
const allow = {
|
|
9319
|
+
"*": []
|
|
9320
|
+
};
|
|
9321
|
+
const entries = providerEntries();
|
|
9322
|
+
if (entries.length === 0) {
|
|
9323
|
+
return { allow };
|
|
9324
|
+
}
|
|
9325
|
+
const forwardURL = sandboxProxyUrl(input?.requesterToken);
|
|
9326
|
+
for (const entry of entries) {
|
|
9327
|
+
for (const domain of entry.domains) {
|
|
9328
|
+
allow[domain] = [{ forwardURL }];
|
|
9329
|
+
}
|
|
9330
|
+
}
|
|
9331
|
+
return { allow };
|
|
9332
|
+
}
|
|
9333
|
+
async function resolveSandboxCommandEnvironment() {
|
|
9334
|
+
const env = {};
|
|
9335
|
+
for (const plugin of getPluginProviders().sort(
|
|
9336
|
+
(left, right) => left.manifest.name.localeCompare(right.manifest.name)
|
|
9337
|
+
)) {
|
|
9338
|
+
Object.assign(env, resolvePluginCommandEnv(plugin.manifest));
|
|
9339
|
+
const credentials = plugin.manifest.credentials;
|
|
9340
|
+
if (credentials) {
|
|
9341
|
+
env[credentials.authTokenEnv] = resolveAuthTokenPlaceholder(credentials);
|
|
9342
|
+
}
|
|
9343
|
+
}
|
|
9344
|
+
return env;
|
|
9209
9345
|
}
|
|
9210
9346
|
|
|
9211
9347
|
// src/chat/sandbox/http-error-details.ts
|
|
@@ -10510,7 +10646,6 @@ function createSandboxSessionManager(options) {
|
|
|
10510
10646
|
}
|
|
10511
10647
|
};
|
|
10512
10648
|
const buildToolExecutors = async (sandboxInstance) => {
|
|
10513
|
-
const activeSandboxId = sandboxInstance.sandboxId;
|
|
10514
10649
|
const toolkit = await withSandboxSpan(
|
|
10515
10650
|
"sandbox.bash_tool.init",
|
|
10516
10651
|
"sandbox.tool.init",
|
|
@@ -10530,35 +10665,9 @@ function createSandboxSessionManager(options) {
|
|
|
10530
10665
|
}
|
|
10531
10666
|
return {
|
|
10532
10667
|
bash: async (input) => {
|
|
10533
|
-
const commandEgressId = sandboxInstance.sandboxEgressId;
|
|
10534
10668
|
let timedOut = false;
|
|
10535
10669
|
let timeoutId;
|
|
10536
|
-
let commandFinished = false;
|
|
10537
|
-
const finishCommand = async () => {
|
|
10538
|
-
if (commandFinished) {
|
|
10539
|
-
return;
|
|
10540
|
-
}
|
|
10541
|
-
commandFinished = true;
|
|
10542
|
-
await options?.afterCommand?.(commandEgressId);
|
|
10543
|
-
await refreshNetworkPolicy(sandboxInstance);
|
|
10544
|
-
};
|
|
10545
|
-
const finishCommandBestEffort = async () => {
|
|
10546
|
-
try {
|
|
10547
|
-
await finishCommand();
|
|
10548
|
-
} catch (error) {
|
|
10549
|
-
logWarn(
|
|
10550
|
-
"sandbox_command_cleanup_failed",
|
|
10551
|
-
traceContext,
|
|
10552
|
-
{
|
|
10553
|
-
"app.sandbox.id": activeSandboxId,
|
|
10554
|
-
"error.type": error instanceof Error ? error.name : "sandbox_command_cleanup_error"
|
|
10555
|
-
},
|
|
10556
|
-
"Sandbox command cleanup failed"
|
|
10557
|
-
);
|
|
10558
|
-
}
|
|
10559
|
-
};
|
|
10560
10670
|
try {
|
|
10561
|
-
await options?.beforeCommand?.(commandEgressId);
|
|
10562
10671
|
await refreshNetworkPolicy(sandboxInstance);
|
|
10563
10672
|
const sandboxCommandEnv = await resolveCommandEnv();
|
|
10564
10673
|
const script = buildNonInteractiveShellScript(input.command, {
|
|
@@ -10580,7 +10689,6 @@ function createSandboxSessionManager(options) {
|
|
|
10580
10689
|
cwd: SANDBOX_WORKSPACE_ROOT,
|
|
10581
10690
|
...controller ? { signal: controller.signal } : {}
|
|
10582
10691
|
});
|
|
10583
|
-
await finishCommandBestEffort();
|
|
10584
10692
|
return await readCommandOutput(commandResult2);
|
|
10585
10693
|
} catch (error) {
|
|
10586
10694
|
if (timedOut) {
|
|
@@ -10601,7 +10709,6 @@ function createSandboxSessionManager(options) {
|
|
|
10601
10709
|
if (timeoutId) {
|
|
10602
10710
|
clearTimeout(timeoutId);
|
|
10603
10711
|
}
|
|
10604
|
-
await finishCommandBestEffort();
|
|
10605
10712
|
}
|
|
10606
10713
|
},
|
|
10607
10714
|
readFile: async (input) => await executeReadFile(input, {
|
|
@@ -10690,25 +10797,40 @@ function createSandboxExecutor(options) {
|
|
|
10690
10797
|
let referenceFiles = [];
|
|
10691
10798
|
const traceContext = options?.traceContext ?? {};
|
|
10692
10799
|
const credentialEgress = options?.credentialEgress;
|
|
10693
|
-
const
|
|
10694
|
-
|
|
10695
|
-
|
|
10800
|
+
const sandboxEgressTokenTtlMs = Math.max(
|
|
10801
|
+
1,
|
|
10802
|
+
options?.timeoutMs ?? 1e3 * 60 * 30
|
|
10803
|
+
);
|
|
10804
|
+
const sandboxEgressRequesterTokens = /* @__PURE__ */ new Map();
|
|
10805
|
+
const sandboxEgressRequesterTokenFor = (egressId) => {
|
|
10806
|
+
const cached = sandboxEgressRequesterTokens.get(egressId);
|
|
10807
|
+
if (cached && cached.expiresAtMs > Date.now()) {
|
|
10808
|
+
return cached.token;
|
|
10809
|
+
}
|
|
10810
|
+
if (!credentialEgress) {
|
|
10811
|
+
throw new Error("Sandbox credential egress is not configured");
|
|
10812
|
+
}
|
|
10813
|
+
const now = Date.now();
|
|
10814
|
+
const token = createSandboxEgressRequesterToken({
|
|
10696
10815
|
requesterId: credentialEgress.requesterId,
|
|
10697
|
-
|
|
10816
|
+
egressId,
|
|
10817
|
+
ttlMs: sandboxEgressTokenTtlMs
|
|
10818
|
+
});
|
|
10819
|
+
sandboxEgressRequesterTokens.set(egressId, {
|
|
10820
|
+
expiresAtMs: now + sandboxEgressTokenTtlMs,
|
|
10821
|
+
token
|
|
10698
10822
|
});
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
await clearSandboxEgressSession(egressId);
|
|
10702
|
-
} : void 0;
|
|
10823
|
+
return token;
|
|
10824
|
+
};
|
|
10703
10825
|
const sessionManager = createSandboxSessionManager({
|
|
10704
10826
|
sandboxId: options?.sandboxId,
|
|
10705
10827
|
sandboxDependencyProfileHash: options?.sandboxDependencyProfileHash,
|
|
10706
10828
|
timeoutMs: options?.timeoutMs,
|
|
10707
10829
|
traceContext,
|
|
10708
10830
|
commandEnv: credentialEgress ? async () => await resolveSandboxCommandEnvironment() : void 0,
|
|
10709
|
-
createNetworkPolicy: credentialEgress ?
|
|
10710
|
-
|
|
10711
|
-
|
|
10831
|
+
createNetworkPolicy: credentialEgress ? (egressId) => buildSandboxEgressNetworkPolicy({
|
|
10832
|
+
requesterToken: sandboxEgressRequesterTokenFor(egressId)
|
|
10833
|
+
}) : void 0,
|
|
10712
10834
|
onSandboxAcquired: async (sandbox) => {
|
|
10713
10835
|
await options?.onSandboxAcquired?.(sandbox);
|
|
10714
10836
|
}
|
|
@@ -13081,7 +13203,8 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
13081
13203
|
config: botConfig.advisor,
|
|
13082
13204
|
conversationId: sessionConversationId,
|
|
13083
13205
|
logContext: spanContext,
|
|
13084
|
-
getTools: () => advisorTools
|
|
13206
|
+
getTools: () => advisorTools,
|
|
13207
|
+
streamFn: createTracedStreamFn()
|
|
13085
13208
|
}
|
|
13086
13209
|
}
|
|
13087
13210
|
);
|
|
@@ -13174,6 +13297,7 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
13174
13297
|
);
|
|
13175
13298
|
agent = new Agent2({
|
|
13176
13299
|
getApiKey: () => getPiGatewayApiKeyOverride(),
|
|
13300
|
+
streamFn: createTracedStreamFn(),
|
|
13177
13301
|
initialState: {
|
|
13178
13302
|
systemPrompt: baseInstructions,
|
|
13179
13303
|
model: resolveGatewayModel(botConfig.modelId),
|
|
@@ -14834,7 +14958,7 @@ async function persistAuthPauseTurnState(args) {
|
|
|
14834
14958
|
}
|
|
14835
14959
|
|
|
14836
14960
|
// src/chat/services/timeout-resume.ts
|
|
14837
|
-
import { createHmac, timingSafeEqual } from "crypto";
|
|
14961
|
+
import { createHmac as createHmac2, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
14838
14962
|
var TURN_TIMEOUT_RESUME_PATH = "/api/internal/turn-resume";
|
|
14839
14963
|
var TURN_TIMEOUT_RESUME_SIGNATURE_VERSION = "v1";
|
|
14840
14964
|
var TURN_TIMEOUT_RESUME_MAX_SKEW_MS = 5 * 60 * 1e3;
|
|
@@ -14869,16 +14993,16 @@ function buildSignedPayload(timestamp, body) {
|
|
|
14869
14993
|
return `${timestamp}:${body}`;
|
|
14870
14994
|
}
|
|
14871
14995
|
function signTurnTimeoutResumeBody(secret, timestamp, body) {
|
|
14872
|
-
const digest =
|
|
14996
|
+
const digest = createHmac2("sha256", secret).update(buildSignedPayload(timestamp, body)).digest("hex");
|
|
14873
14997
|
return `${TURN_TIMEOUT_RESUME_SIGNATURE_VERSION}=${digest}`;
|
|
14874
14998
|
}
|
|
14875
|
-
function
|
|
14999
|
+
function timingSafeMatch2(expected, actual) {
|
|
14876
15000
|
const expectedBuffer = Buffer.from(expected);
|
|
14877
15001
|
const actualBuffer = Buffer.from(actual);
|
|
14878
15002
|
if (expectedBuffer.length !== actualBuffer.length) {
|
|
14879
15003
|
return false;
|
|
14880
15004
|
}
|
|
14881
|
-
return
|
|
15005
|
+
return timingSafeEqual2(expectedBuffer, actualBuffer);
|
|
14882
15006
|
}
|
|
14883
15007
|
function parseTurnTimeoutResumeRequest(value) {
|
|
14884
15008
|
if (!value || typeof value !== "object") {
|
|
@@ -14941,7 +15065,7 @@ async function verifyTurnTimeoutResumeRequest(request) {
|
|
|
14941
15065
|
}
|
|
14942
15066
|
const body = await request.text();
|
|
14943
15067
|
const expectedSignature = signTurnTimeoutResumeBody(secret, timestamp, body);
|
|
14944
|
-
if (!
|
|
15068
|
+
if (!timingSafeMatch2(expectedSignature, signature)) {
|
|
14945
15069
|
return void 0;
|
|
14946
15070
|
}
|
|
14947
15071
|
try {
|
|
@@ -15976,10 +16100,32 @@ function egressAttributes(input) {
|
|
|
15976
16100
|
...input.status ? { "http.response.status_code": input.status } : {}
|
|
15977
16101
|
};
|
|
15978
16102
|
}
|
|
16103
|
+
function requesterTokenFromRequest(request) {
|
|
16104
|
+
const pathname = new URL(request.url).pathname;
|
|
16105
|
+
const prefix = `${SANDBOX_EGRESS_PROXY_PATH}/`;
|
|
16106
|
+
if (!pathname.startsWith(prefix)) {
|
|
16107
|
+
return void 0;
|
|
16108
|
+
}
|
|
16109
|
+
const token = pathname.slice(prefix.length).split("/")[0];
|
|
16110
|
+
if (!token) {
|
|
16111
|
+
return void 0;
|
|
16112
|
+
}
|
|
16113
|
+
try {
|
|
16114
|
+
return decodeURIComponent(token);
|
|
16115
|
+
} catch {
|
|
16116
|
+
return void 0;
|
|
16117
|
+
}
|
|
16118
|
+
}
|
|
16119
|
+
function redactedProxyPath(pathname) {
|
|
16120
|
+
if (pathname.startsWith(`${SANDBOX_EGRESS_PROXY_PATH}/`)) {
|
|
16121
|
+
return `${SANDBOX_EGRESS_PROXY_PATH}/<token>`;
|
|
16122
|
+
}
|
|
16123
|
+
return pathname;
|
|
16124
|
+
}
|
|
15979
16125
|
function routingAttributes(request, upstreamUrl) {
|
|
15980
16126
|
const proxyUrl = new URL(request.url);
|
|
15981
16127
|
const attributes = {
|
|
15982
|
-
"app.sandbox.egress.proxy_path": proxyUrl.pathname
|
|
16128
|
+
"app.sandbox.egress.proxy_path": redactedProxyPath(proxyUrl.pathname)
|
|
15983
16129
|
};
|
|
15984
16130
|
if (upstreamUrl) {
|
|
15985
16131
|
attributes["app.sandbox.egress.upstream_path"] = upstreamUrl.pathname;
|
|
@@ -16032,22 +16178,23 @@ function normalizePort(value) {
|
|
|
16032
16178
|
function sandboxIdFromPayload(payload) {
|
|
16033
16179
|
return typeof payload.sandbox_id === "string" ? payload.sandbox_id : void 0;
|
|
16034
16180
|
}
|
|
16181
|
+
function normalizedForwardedPath(path11) {
|
|
16182
|
+
if (!path11.startsWith("/") || path11.startsWith("//") || path11.includes("#") || /[\r\n]/.test(path11)) {
|
|
16183
|
+
return { ok: false, error: "Invalid forwarded path" };
|
|
16184
|
+
}
|
|
16185
|
+
try {
|
|
16186
|
+
const url = new URL(path11, "https://sandbox-forwarded.local");
|
|
16187
|
+
return { ok: true, path: `${url.pathname}${url.search}` };
|
|
16188
|
+
} catch {
|
|
16189
|
+
return { ok: false, error: "Invalid forwarded path" };
|
|
16190
|
+
}
|
|
16191
|
+
}
|
|
16035
16192
|
function upstreamPath(request) {
|
|
16036
16193
|
const forwardedPath = request.headers.get(FORWARDED_PATH_HEADER);
|
|
16037
|
-
if (forwardedPath?.trim()) {
|
|
16038
|
-
|
|
16039
|
-
if (!path11.startsWith("/") || path11.startsWith("//") || path11.includes("#") || /[\r\n]/.test(path11)) {
|
|
16040
|
-
return { ok: false, error: "Invalid forwarded path" };
|
|
16041
|
-
}
|
|
16042
|
-
try {
|
|
16043
|
-
const url2 = new URL(path11, "https://sandbox-forwarded.local");
|
|
16044
|
-
return { ok: true, path: `${url2.pathname}${url2.search}` };
|
|
16045
|
-
} catch {
|
|
16046
|
-
return { ok: false, error: "Invalid forwarded path" };
|
|
16047
|
-
}
|
|
16194
|
+
if (!forwardedPath?.trim()) {
|
|
16195
|
+
return { ok: false, error: "Missing forwarded path" };
|
|
16048
16196
|
}
|
|
16049
|
-
|
|
16050
|
-
return { ok: true, path: `${url.pathname}${url.search}` };
|
|
16197
|
+
return normalizedForwardedPath(forwardedPath.trim());
|
|
16051
16198
|
}
|
|
16052
16199
|
function buildUpstreamUrl(request) {
|
|
16053
16200
|
const forwardedHost = request.headers.get(FORWARDED_HOST_HEADER);
|
|
@@ -16119,18 +16266,14 @@ function responseHeaders(upstream) {
|
|
|
16119
16266
|
});
|
|
16120
16267
|
return headers;
|
|
16121
16268
|
}
|
|
16122
|
-
async function credentialLease(
|
|
16123
|
-
const cached = await getSandboxEgressCredentialLease(
|
|
16124
|
-
egressId,
|
|
16125
|
-
provider,
|
|
16126
|
-
session
|
|
16127
|
-
);
|
|
16269
|
+
async function credentialLease(provider, context) {
|
|
16270
|
+
const cached = await getSandboxEgressCredentialLease(provider, context);
|
|
16128
16271
|
if (cached) {
|
|
16129
16272
|
return cached;
|
|
16130
16273
|
}
|
|
16131
16274
|
const lease = await issueProviderCredentialLease({
|
|
16132
16275
|
provider,
|
|
16133
|
-
requesterId:
|
|
16276
|
+
requesterId: context.requesterId,
|
|
16134
16277
|
reason: `sandbox-egress:${provider}`
|
|
16135
16278
|
});
|
|
16136
16279
|
const headerTransforms = lease.headerTransforms ?? [];
|
|
@@ -16144,7 +16287,7 @@ async function credentialLease(egressId, provider, session) {
|
|
|
16144
16287
|
expiresAt: lease.expiresAt,
|
|
16145
16288
|
headerTransforms
|
|
16146
16289
|
};
|
|
16147
|
-
await setSandboxEgressCredentialLease(
|
|
16290
|
+
await setSandboxEgressCredentialLease(context, cachedLease);
|
|
16148
16291
|
return cachedLease;
|
|
16149
16292
|
}
|
|
16150
16293
|
function hasTransformForHost(lease, host) {
|
|
@@ -16185,7 +16328,7 @@ async function proxySandboxEgressRequest(request, deps = {}) {
|
|
|
16185
16328
|
{},
|
|
16186
16329
|
{
|
|
16187
16330
|
"http.request.method": request.method,
|
|
16188
|
-
"url.path": new URL(request.url).pathname
|
|
16331
|
+
"url.path": redactedProxyPath(new URL(request.url).pathname)
|
|
16189
16332
|
},
|
|
16190
16333
|
"Sandbox egress OIDC payload did not include a VM session id"
|
|
16191
16334
|
);
|
|
@@ -16203,7 +16346,7 @@ async function proxySandboxEgressRequest(request, deps = {}) {
|
|
|
16203
16346
|
...egressAttributes({
|
|
16204
16347
|
egressId: activeEgressId,
|
|
16205
16348
|
method: request.method,
|
|
16206
|
-
path: new URL(request.url).pathname,
|
|
16349
|
+
path: redactedProxyPath(new URL(request.url).pathname),
|
|
16207
16350
|
status: 400
|
|
16208
16351
|
}),
|
|
16209
16352
|
...routingAttributes(request)
|
|
@@ -16232,10 +16375,12 @@ async function proxySandboxEgressRequest(request, deps = {}) {
|
|
|
16232
16375
|
);
|
|
16233
16376
|
return jsonError("No provider owns forwarded host", 403);
|
|
16234
16377
|
}
|
|
16235
|
-
const
|
|
16236
|
-
|
|
16378
|
+
const requesterContext = parseSandboxEgressRequesterToken(
|
|
16379
|
+
requesterTokenFromRequest(request)
|
|
16380
|
+
);
|
|
16381
|
+
if (!requesterContext || requesterContext.egressId !== activeEgressId) {
|
|
16237
16382
|
logWarn(
|
|
16238
|
-
"
|
|
16383
|
+
"sandbox_egress_requester_context_unauthorized",
|
|
16239
16384
|
{},
|
|
16240
16385
|
{
|
|
16241
16386
|
...egressAttributes({
|
|
@@ -16248,13 +16393,13 @@ async function proxySandboxEgressRequest(request, deps = {}) {
|
|
|
16248
16393
|
}),
|
|
16249
16394
|
...routingAttributes(request, upstreamUrl)
|
|
16250
16395
|
},
|
|
16251
|
-
"Sandbox egress
|
|
16396
|
+
"Sandbox egress request did not include a valid requester context for the VM session"
|
|
16252
16397
|
);
|
|
16253
|
-
return jsonError("Sandbox egress
|
|
16398
|
+
return jsonError("Sandbox egress requester context is not authorized", 403);
|
|
16254
16399
|
}
|
|
16255
16400
|
let lease;
|
|
16256
16401
|
try {
|
|
16257
|
-
lease = await credentialLease(
|
|
16402
|
+
lease = await credentialLease(provider, requesterContext);
|
|
16258
16403
|
} catch (error) {
|
|
16259
16404
|
if (error instanceof CredentialUnavailableError) {
|
|
16260
16405
|
logWarn(
|
|
@@ -16358,7 +16503,7 @@ ${error.message}`,
|
|
|
16358
16503
|
},
|
|
16359
16504
|
"Sandbox egress upstream auth rejected"
|
|
16360
16505
|
);
|
|
16361
|
-
await clearSandboxEgressCredentialLease(
|
|
16506
|
+
await clearSandboxEgressCredentialLease(provider, requesterContext);
|
|
16362
16507
|
}
|
|
16363
16508
|
return new Response(upstream.body, {
|
|
16364
16509
|
status: upstream.status,
|
package/dist/cli/check.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parseSkillFile
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-ZNFNY53B.js";
|
|
4
4
|
import {
|
|
5
5
|
parsePluginManifest
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-Q3FDONU7.js";
|
|
7
7
|
import "../chunk-Z3YD6NHK.js";
|
|
8
8
|
import "../chunk-XPXD3FCE.js";
|
|
9
9
|
import "../chunk-2KG3PWR4.js";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
disconnectStateAdapter,
|
|
3
3
|
resolveRuntimeDependencySnapshot
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-KCOKQLBF.js";
|
|
5
5
|
import {
|
|
6
6
|
getPluginProviders,
|
|
7
7
|
getPluginRuntimeDependencies,
|
|
8
8
|
getPluginRuntimePostinstall
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-Q3FDONU7.js";
|
|
10
10
|
import "../chunk-Z3YD6NHK.js";
|
|
11
11
|
import "../chunk-XPXD3FCE.js";
|
|
12
12
|
import "../chunk-2KG3PWR4.js";
|
package/dist/instrumentation.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@sentry/node": ">=10.0.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@sentry/node": "10.
|
|
49
|
+
"@sentry/node": "10.53.1",
|
|
50
50
|
"@types/node": "^25.6.0",
|
|
51
51
|
"dependency-cruiser": "^17.4.0",
|
|
52
52
|
"msw": "^2.14.3",
|