@opengeni/api-router 4.0.0 → 4.1.0-canary.35855175602001
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 +1 -1
- package/dist/{chunk-E7TZFJ65.js → chunk-24C5LPNE.js} +808 -577
- package/dist/{chunk-E7TZFJ65.js.map → chunk-24C5LPNE.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/integrations/github-lens-connect.d.ts +1 -1
- package/dist/integrations/oauth-client.d.ts +1 -1
- package/dist/integrations/slack-bot.d.ts +8 -0
- package/dist/integrations/slack-interactions.d.ts +1 -1
- package/dist/mcp/child-read-evidence.d.ts +9 -0
- package/dist/mcp/first-party-tool-permissions.d.ts +3 -0
- package/dist/mcp/session-wait.d.ts +2 -0
- package/dist/routes/codex.d.ts +2 -1
- package/package.json +19 -19
- package/src/integrations/oauth-client.ts +68 -5
- package/src/integrations/slack-bot.ts +32 -3
- package/src/integrations/slack-interactions.ts +79 -8
- package/src/mcp/child-read-evidence.ts +19 -0
- package/src/mcp/first-party-tool-permissions.ts +1 -0
- package/src/mcp/server.ts +175 -101
- package/src/mcp/session-wait.ts +17 -0
- package/src/routes/codex.ts +19 -12
- package/src/routes/skill-content.ts +21 -5
- package/src/sandbox/machines.ts +9 -8
- package/src/sandbox-file-artifacts.ts +15 -1
- package/src/site-uploads.ts +19 -4
|
@@ -267,6 +267,7 @@ var FIRST_PARTY_TOOL_AUTHORIZATION = {
|
|
|
267
267
|
run_on: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
268
268
|
sandbox_provision: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
269
269
|
connected_machine_remove: { allOf: ["enrollments:manage"] },
|
|
270
|
+
connected_machine_enroll_token: { allOf: ["enrollments:manage"] },
|
|
270
271
|
rig_list: { allOf: ["rigs:use"] },
|
|
271
272
|
rig_get: { allOf: ["rigs:use"] },
|
|
272
273
|
rig_propose_change: { allOf: ["rigs:use"] },
|
|
@@ -649,8 +650,8 @@ import { SiteSessionPathError, OrganizationIntegrationDeniedError as Organizatio
|
|
|
649
650
|
|
|
650
651
|
// src/routes/model-connection-access.ts
|
|
651
652
|
import {
|
|
652
|
-
configuredModels as
|
|
653
|
-
withCodexCatalogProvider,
|
|
653
|
+
configuredModels as configuredModels3,
|
|
654
|
+
withCodexCatalogProvider as withCodexCatalogProvider2,
|
|
654
655
|
withXaiSubscriptionCatalogProvider as withXaiSubscriptionCatalogProvider2,
|
|
655
656
|
withOrganizationGatewayCatalogProvider,
|
|
656
657
|
withOrganizationOpenRouterCatalogProvider
|
|
@@ -673,14 +674,17 @@ import { HTTPException as HTTPException4 } from "hono/http-exception";
|
|
|
673
674
|
import { z as z5 } from "zod";
|
|
674
675
|
|
|
675
676
|
// src/routes/codex.ts
|
|
676
|
-
import {
|
|
677
|
+
import {
|
|
678
|
+
environmentsEncryptionKeyBytes,
|
|
679
|
+
configuredModels,
|
|
680
|
+
getSettings,
|
|
681
|
+
withCodexCatalogProvider
|
|
682
|
+
} from "@opengeni/config";
|
|
677
683
|
import {
|
|
678
684
|
accessTokenExpiry,
|
|
679
685
|
buildCodexUsageWindowFromCache,
|
|
680
686
|
CODEX_CLIENT_VERSION,
|
|
681
|
-
CODEX_FALLBACK_MODEL_SLUGS,
|
|
682
687
|
CODEX_FIVE_HOUR_WINDOW_SECONDS,
|
|
683
|
-
CODEX_MODEL_ID_PREFIX,
|
|
684
688
|
CODEX_PROVIDER_ID,
|
|
685
689
|
CODEX_WEEKLY_WINDOW_SECONDS,
|
|
686
690
|
CodexDeviceError,
|
|
@@ -741,7 +745,8 @@ import {
|
|
|
741
745
|
getManagedSession,
|
|
742
746
|
hasPermission as hasPermission2,
|
|
743
747
|
requireAccessGrant as requireAccessGrant2,
|
|
744
|
-
requireCanonicalLocalAccountAdministrator
|
|
748
|
+
requireCanonicalLocalAccountAdministrator,
|
|
749
|
+
resolveCatalogSettings
|
|
745
750
|
} from "@opengeni/core";
|
|
746
751
|
import { HTTPException as HTTPException2 } from "hono/http-exception";
|
|
747
752
|
import * as z3 from "zod/v4";
|
|
@@ -863,10 +868,10 @@ function codexWorkerReadiness(input) {
|
|
|
863
868
|
function codexUsageJson(payload) {
|
|
864
869
|
return { status: payload.status, usage: payload };
|
|
865
870
|
}
|
|
866
|
-
function codexModelsForPicker() {
|
|
867
|
-
return
|
|
868
|
-
id:
|
|
869
|
-
label:
|
|
871
|
+
function codexModelsForPicker(settings = getSettings()) {
|
|
872
|
+
return configuredModels(withCodexCatalogProvider(settings)).filter((model) => model.providerId === CODEX_PROVIDER_ID).map((model) => ({
|
|
873
|
+
id: model.id,
|
|
874
|
+
label: model.label,
|
|
870
875
|
provider: CODEX_PROVIDER_ID,
|
|
871
876
|
providerLabel: CODEX_PROVIDER_LABEL,
|
|
872
877
|
api: "responses"
|
|
@@ -1687,7 +1692,7 @@ function registerCodexRoutes(app, deps) {
|
|
|
1687
1692
|
now: /* @__PURE__ */ new Date()
|
|
1688
1693
|
});
|
|
1689
1694
|
let valid = false;
|
|
1690
|
-
const models = codexModelsForPicker();
|
|
1695
|
+
const models = codexModelsForPicker((await resolveCatalogSettings(db, settings)).settings);
|
|
1691
1696
|
let catalogError = null;
|
|
1692
1697
|
try {
|
|
1693
1698
|
const cred = status?.credentialId ? await loadCodexCredentialForRun(db, settings, workspaceId, status.credentialId) : null;
|
|
@@ -2471,7 +2476,7 @@ import {
|
|
|
2471
2476
|
updateOrganizationXaiRotation
|
|
2472
2477
|
} from "@opengeni/db";
|
|
2473
2478
|
import {
|
|
2474
|
-
configuredModels,
|
|
2479
|
+
configuredModels as configuredModels2,
|
|
2475
2480
|
environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes2,
|
|
2476
2481
|
withXaiSubscriptionCatalogProvider
|
|
2477
2482
|
} from "@opengeni/config";
|
|
@@ -3184,7 +3189,7 @@ function registerSuperGrokRoutes(app, deps) {
|
|
|
3184
3189
|
valid = false;
|
|
3185
3190
|
}
|
|
3186
3191
|
const catalogSettings = valid ? (await deps.resolveCatalogSettings()).settings : null;
|
|
3187
|
-
const catalog = catalogSettings ?
|
|
3192
|
+
const catalog = catalogSettings ? configuredModels2(withXaiSubscriptionCatalogProvider(catalogSettings)).filter(
|
|
3188
3193
|
(model) => model.credentialSource.kind === "connected_subscription" && model.credentialSource.provider === "xai"
|
|
3189
3194
|
).map(projectClientModel) : [];
|
|
3190
3195
|
return c.json({
|
|
@@ -3426,7 +3431,7 @@ function registerModelConnectionAccessRoutes(app, deps) {
|
|
|
3426
3431
|
accountId: connection.accountId,
|
|
3427
3432
|
workspaceId: connection.workspaceId
|
|
3428
3433
|
})).settings;
|
|
3429
|
-
settings =
|
|
3434
|
+
settings = withCodexCatalogProvider2(withXaiSubscriptionCatalogProvider2(settings));
|
|
3430
3435
|
let workspaces = [];
|
|
3431
3436
|
if (connection.workspaceId === null) {
|
|
3432
3437
|
const actor = {
|
|
@@ -3448,7 +3453,7 @@ function registerModelConnectionAccessRoutes(app, deps) {
|
|
|
3448
3453
|
ModelConnectionAccessResponse.parse({
|
|
3449
3454
|
policy,
|
|
3450
3455
|
workspaces,
|
|
3451
|
-
models:
|
|
3456
|
+
models: configuredModels3(settings).filter((model) => model.id.startsWith(modelPrefix(connection))).map(({ id, label }) => ({ id, label })),
|
|
3452
3457
|
personalWorkspacesSupported: connection.workspaceId === null && (connection.kind === "codex" || connection.kind === "supergrok")
|
|
3453
3458
|
})
|
|
3454
3459
|
);
|
|
@@ -3482,10 +3487,10 @@ import {
|
|
|
3482
3487
|
canonicalizeConfiguredModelId as canonicalizeConfiguredModelId2,
|
|
3483
3488
|
configuredAllowedModels,
|
|
3484
3489
|
configuredAllowedReasoningEfforts,
|
|
3485
|
-
configuredModels as
|
|
3490
|
+
configuredModels as configuredModels4,
|
|
3486
3491
|
resolveFirstPartyMcpToolPolicy as resolveFirstPartyMcpToolPolicy2,
|
|
3487
3492
|
resolveVoiceInputProviderRegistry as resolveVoiceInputProviderRegistry2,
|
|
3488
|
-
withCodexCatalogProvider as
|
|
3493
|
+
withCodexCatalogProvider as withCodexCatalogProvider3,
|
|
3489
3494
|
withXaiSubscriptionCatalogProvider as withXaiSubscriptionCatalogProvider3
|
|
3490
3495
|
} from "@opengeni/config";
|
|
3491
3496
|
import {
|
|
@@ -3600,7 +3605,7 @@ import {
|
|
|
3600
3605
|
requireAccessGrantAuthorization as requireAccessGrantAuthorization36,
|
|
3601
3606
|
requirePermission as requirePermission9,
|
|
3602
3607
|
releaseManagedAuthRequestActorLease,
|
|
3603
|
-
resolveCatalogSettings,
|
|
3608
|
+
resolveCatalogSettings as resolveCatalogSettings2,
|
|
3604
3609
|
resolveWorkspaceCatalogSettings as resolveWorkspaceCatalogSettings10,
|
|
3605
3610
|
validateManagedAuthRequestActorLease,
|
|
3606
3611
|
requireSessionAuthorization as requireSessionAuthorization16,
|
|
@@ -5889,7 +5894,296 @@ import {
|
|
|
5889
5894
|
deleteChannel,
|
|
5890
5895
|
setSessionChannel
|
|
5891
5896
|
} from "@opengeni/db";
|
|
5892
|
-
import { createHash as
|
|
5897
|
+
import { createHash as createHash12, randomUUID as randomUUID3 } from "crypto";
|
|
5898
|
+
|
|
5899
|
+
// src/sandbox/enrollment.ts
|
|
5900
|
+
import { randomBytes } from "crypto";
|
|
5901
|
+
import {
|
|
5902
|
+
resolveEnrollmentSigningSecret,
|
|
5903
|
+
resolveRelayTokenSecret
|
|
5904
|
+
} from "@opengeni/config";
|
|
5905
|
+
import {
|
|
5906
|
+
DeviceEnrollmentState,
|
|
5907
|
+
signEnrollmentBearer,
|
|
5908
|
+
signEnrollToken,
|
|
5909
|
+
signRelayToken,
|
|
5910
|
+
verifyEnrollToken
|
|
5911
|
+
} from "@opengeni/contracts";
|
|
5912
|
+
import {
|
|
5913
|
+
approveDeviceEnrollmentRequest,
|
|
5914
|
+
consumeDeviceEnrollmentRequest,
|
|
5915
|
+
createDeviceEnrollmentRequest,
|
|
5916
|
+
denyDeviceEnrollmentRequest,
|
|
5917
|
+
finalizeEnrollmentByToken,
|
|
5918
|
+
getDeviceEnrollmentRequestByDeviceCode,
|
|
5919
|
+
getEnrollment,
|
|
5920
|
+
getPendingDeviceEnrollmentRequestByUserCode,
|
|
5921
|
+
getPendingDeviceEnrollmentRequestByUserCodeGlobal
|
|
5922
|
+
} from "@opengeni/db";
|
|
5923
|
+
import { relayDialBaseFromSettings } from "@opengeni/core";
|
|
5924
|
+
var DEVICE_CODE_TTL_SECONDS = 600;
|
|
5925
|
+
var DEVICE_POLL_INTERVAL_SECONDS = 5;
|
|
5926
|
+
var ENROLLMENT_BEARER_TTL_SECONDS = 30 * 24 * 3600;
|
|
5927
|
+
var RELAY_TOKEN_TTL_SECONDS = 30 * 24 * 3600;
|
|
5928
|
+
var ENROLL_TOKEN_TTL_SECONDS = 3600;
|
|
5929
|
+
function mintDeviceCode() {
|
|
5930
|
+
return randomBytes(32).toString("base64url");
|
|
5931
|
+
}
|
|
5932
|
+
var USER_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
5933
|
+
function mintUserCode() {
|
|
5934
|
+
const bytes = randomBytes(8);
|
|
5935
|
+
let out = "";
|
|
5936
|
+
for (let i = 0; i < 8; i += 1) {
|
|
5937
|
+
out += USER_CODE_ALPHABET[bytes[i] % USER_CODE_ALPHABET.length];
|
|
5938
|
+
}
|
|
5939
|
+
return `${out.slice(0, 4)}-${out.slice(4, 8)}`;
|
|
5940
|
+
}
|
|
5941
|
+
async function startDeviceEnrollment(services, input) {
|
|
5942
|
+
const { db } = services;
|
|
5943
|
+
const expiresAt = new Date(Date.now() + DEVICE_CODE_TTL_SECONDS * 1e3);
|
|
5944
|
+
let request;
|
|
5945
|
+
let lastError;
|
|
5946
|
+
for (let attempt = 0; attempt < 5 && !request; attempt += 1) {
|
|
5947
|
+
const deviceCode = mintDeviceCode();
|
|
5948
|
+
const userCode = mintUserCode();
|
|
5949
|
+
try {
|
|
5950
|
+
request = await createDeviceEnrollmentRequest(db, {
|
|
5951
|
+
accountId: input.accountId,
|
|
5952
|
+
workspaceId: input.workspaceId,
|
|
5953
|
+
deviceCode,
|
|
5954
|
+
userCode,
|
|
5955
|
+
pubkey: input.publicKey,
|
|
5956
|
+
os: input.os,
|
|
5957
|
+
arch: input.arch,
|
|
5958
|
+
machineName: input.machineName ?? null,
|
|
5959
|
+
requestedExposure: "whole-machine",
|
|
5960
|
+
canOfferDisplay: input.canOfferDisplay,
|
|
5961
|
+
requestsScreenControl: input.requestsScreenControl,
|
|
5962
|
+
expiresAt
|
|
5963
|
+
});
|
|
5964
|
+
} catch (error) {
|
|
5965
|
+
lastError = error;
|
|
5966
|
+
}
|
|
5967
|
+
}
|
|
5968
|
+
if (!request) {
|
|
5969
|
+
throw lastError instanceof Error ? lastError : new Error("failed to start device enrollment");
|
|
5970
|
+
}
|
|
5971
|
+
const base = input.verificationOrigin.replace(/\/+$/, "");
|
|
5972
|
+
const verificationUri = `${base}/device`;
|
|
5973
|
+
const verificationUriComplete = `${verificationUri}?user_code=${encodeURIComponent(request.userCode)}`;
|
|
5974
|
+
return {
|
|
5975
|
+
deviceCode: request.deviceCode,
|
|
5976
|
+
userCode: request.userCode,
|
|
5977
|
+
verificationUri,
|
|
5978
|
+
verificationUriComplete,
|
|
5979
|
+
intervalSeconds: DEVICE_POLL_INTERVAL_SECONDS,
|
|
5980
|
+
expiresInSeconds: DEVICE_CODE_TTL_SECONDS
|
|
5981
|
+
};
|
|
5982
|
+
}
|
|
5983
|
+
async function approveDeviceEnrollment(services, input) {
|
|
5984
|
+
const { db } = services;
|
|
5985
|
+
const pending = await getPendingDeviceEnrollmentRequestByUserCode(
|
|
5986
|
+
db,
|
|
5987
|
+
input.workspaceId,
|
|
5988
|
+
input.userCode
|
|
5989
|
+
);
|
|
5990
|
+
if (!pending) {
|
|
5991
|
+
return null;
|
|
5992
|
+
}
|
|
5993
|
+
const sandboxName = (pending.machineName?.trim() || `${pending.os} machine`).slice(0, 256);
|
|
5994
|
+
const result = await approveDeviceEnrollmentRequest(db, {
|
|
5995
|
+
accountId: input.accountId,
|
|
5996
|
+
workspaceId: input.workspaceId,
|
|
5997
|
+
...input.scope ? { scope: input.scope } : {},
|
|
5998
|
+
allowOrganization: input.allowOrganization === true,
|
|
5999
|
+
requestId: pending.id,
|
|
6000
|
+
allowScreenControl: input.allowScreenControl,
|
|
6001
|
+
approvedBySubjectId: input.approvedBySubjectId,
|
|
6002
|
+
approvedBySubjectLabel: input.approvedBySubjectLabel ?? null,
|
|
6003
|
+
sandboxName
|
|
6004
|
+
});
|
|
6005
|
+
if (!result.approved || !result.enrollment || !result.sandbox) {
|
|
6006
|
+
return null;
|
|
6007
|
+
}
|
|
6008
|
+
return {
|
|
6009
|
+
enrollmentId: result.enrollment.id,
|
|
6010
|
+
sandboxId: result.sandbox.id,
|
|
6011
|
+
allowScreenControl: result.enrollment.allowScreenControl
|
|
6012
|
+
};
|
|
6013
|
+
}
|
|
6014
|
+
async function lookupDeviceEnrollment(services, input) {
|
|
6015
|
+
const { db } = services;
|
|
6016
|
+
return await getPendingDeviceEnrollmentRequestByUserCodeGlobal(db, input.userCode);
|
|
6017
|
+
}
|
|
6018
|
+
function toLookupResponse(record6) {
|
|
6019
|
+
return {
|
|
6020
|
+
workspaceId: record6.workspaceId,
|
|
6021
|
+
userCode: record6.userCode,
|
|
6022
|
+
machine: {
|
|
6023
|
+
machineName: record6.machineName,
|
|
6024
|
+
os: record6.os,
|
|
6025
|
+
arch: record6.arch,
|
|
6026
|
+
canOfferDisplay: record6.canOfferDisplay,
|
|
6027
|
+
requestsScreenControl: record6.requestsScreenControl
|
|
6028
|
+
},
|
|
6029
|
+
expiresAt: record6.expiresAt
|
|
6030
|
+
};
|
|
6031
|
+
}
|
|
6032
|
+
async function denyDeviceEnrollment(services, input) {
|
|
6033
|
+
const { db } = services;
|
|
6034
|
+
const pending = await getPendingDeviceEnrollmentRequestByUserCode(
|
|
6035
|
+
db,
|
|
6036
|
+
input.workspaceId,
|
|
6037
|
+
input.userCode
|
|
6038
|
+
);
|
|
6039
|
+
if (!pending) {
|
|
6040
|
+
return { denied: false };
|
|
6041
|
+
}
|
|
6042
|
+
return await denyDeviceEnrollmentRequest(db, {
|
|
6043
|
+
accountId: input.accountId,
|
|
6044
|
+
workspaceId: input.workspaceId,
|
|
6045
|
+
requestId: pending.id
|
|
6046
|
+
});
|
|
6047
|
+
}
|
|
6048
|
+
async function mintEnrollToken(services, input) {
|
|
6049
|
+
const { settings } = services;
|
|
6050
|
+
const secret = resolveEnrollmentSigningSecret(settings);
|
|
6051
|
+
if (!secret) {
|
|
6052
|
+
return null;
|
|
6053
|
+
}
|
|
6054
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
6055
|
+
const exp = nowSeconds + ENROLL_TOKEN_TTL_SECONDS;
|
|
6056
|
+
const token = await signEnrollToken(secret, {
|
|
6057
|
+
typ: "enroll",
|
|
6058
|
+
workspaceId: input.workspaceId,
|
|
6059
|
+
accountId: input.accountId,
|
|
6060
|
+
allowScreenControl: input.allowScreenControl,
|
|
6061
|
+
iat: nowSeconds,
|
|
6062
|
+
exp
|
|
6063
|
+
});
|
|
6064
|
+
return {
|
|
6065
|
+
token,
|
|
6066
|
+
expiresAt: new Date(exp * 1e3).toISOString(),
|
|
6067
|
+
expiresInSeconds: ENROLL_TOKEN_TTL_SECONDS
|
|
6068
|
+
};
|
|
6069
|
+
}
|
|
6070
|
+
async function exchangeEnrollToken(services, input) {
|
|
6071
|
+
const { db, settings } = services;
|
|
6072
|
+
const secret = resolveEnrollmentSigningSecret(settings);
|
|
6073
|
+
if (!secret) {
|
|
6074
|
+
return { ok: false, reason: "disabled" };
|
|
6075
|
+
}
|
|
6076
|
+
const claims = await verifyEnrollToken(secret, input.token);
|
|
6077
|
+
if (!claims) {
|
|
6078
|
+
return { ok: false, reason: "invalid" };
|
|
6079
|
+
}
|
|
6080
|
+
const sandboxName = (input.machineName?.trim() || `${input.os} machine`).slice(0, 256);
|
|
6081
|
+
const { enrollment } = await finalizeEnrollmentByToken(db, {
|
|
6082
|
+
accountId: claims.accountId,
|
|
6083
|
+
workspaceId: claims.workspaceId,
|
|
6084
|
+
pubkey: input.publicKey,
|
|
6085
|
+
hasDisplay: input.canOfferDisplay,
|
|
6086
|
+
// The token's allowScreenControl is the AUTHORITATIVE consent (NOT the agent's
|
|
6087
|
+
// requestsScreenControl) — it was baked in at mint by the authorizing user.
|
|
6088
|
+
allowScreenControl: claims.allowScreenControl,
|
|
6089
|
+
os: input.os,
|
|
6090
|
+
arch: input.arch,
|
|
6091
|
+
sandboxName
|
|
6092
|
+
});
|
|
6093
|
+
const credentials = await buildEnrollmentCredentials(services, {
|
|
6094
|
+
secret,
|
|
6095
|
+
workspaceId: claims.workspaceId,
|
|
6096
|
+
agentId: enrollment.id,
|
|
6097
|
+
credentialGeneration: enrollment.credentialGeneration,
|
|
6098
|
+
consentedScreenControl: enrollment.allowScreenControl
|
|
6099
|
+
});
|
|
6100
|
+
return { ok: true, credentials };
|
|
6101
|
+
}
|
|
6102
|
+
async function pollDeviceEnrollment(services, input) {
|
|
6103
|
+
const { db, settings } = services;
|
|
6104
|
+
const request = await getDeviceEnrollmentRequestByDeviceCode(db, input.deviceCode);
|
|
6105
|
+
if (!request) {
|
|
6106
|
+
return { state: "expired" };
|
|
6107
|
+
}
|
|
6108
|
+
if (request.status === "denied") {
|
|
6109
|
+
return { state: "denied" };
|
|
6110
|
+
}
|
|
6111
|
+
if (request.status === "pending") {
|
|
6112
|
+
if (new Date(request.expiresAt).getTime() <= Date.now()) {
|
|
6113
|
+
return { state: "expired" };
|
|
6114
|
+
}
|
|
6115
|
+
return { state: "pending" };
|
|
6116
|
+
}
|
|
6117
|
+
if (!request.enrollmentId) {
|
|
6118
|
+
return { state: "expired" };
|
|
6119
|
+
}
|
|
6120
|
+
const secret = resolveEnrollmentSigningSecret(settings);
|
|
6121
|
+
if (!secret) {
|
|
6122
|
+
return { state: "disabled" };
|
|
6123
|
+
}
|
|
6124
|
+
const enrollment = await getEnrollment(db, request.workspaceId, request.enrollmentId);
|
|
6125
|
+
if (!enrollment || enrollment.status !== "active") {
|
|
6126
|
+
return { state: "denied" };
|
|
6127
|
+
}
|
|
6128
|
+
const credentials = await buildEnrollmentCredentials(services, {
|
|
6129
|
+
secret,
|
|
6130
|
+
workspaceId: request.workspaceId,
|
|
6131
|
+
agentId: enrollment.id,
|
|
6132
|
+
credentialGeneration: enrollment.credentialGeneration,
|
|
6133
|
+
consentedScreenControl: enrollment.allowScreenControl
|
|
6134
|
+
});
|
|
6135
|
+
if (request.status === "approved") {
|
|
6136
|
+
await consumeDeviceEnrollmentRequest(db, {
|
|
6137
|
+
accountId: request.accountId,
|
|
6138
|
+
workspaceId: request.workspaceId,
|
|
6139
|
+
requestId: request.id
|
|
6140
|
+
});
|
|
6141
|
+
}
|
|
6142
|
+
return { state: DeviceEnrollmentState.enum.authorized, credentials };
|
|
6143
|
+
}
|
|
6144
|
+
async function buildEnrollmentCredentials(services, input) {
|
|
6145
|
+
const { settings } = services;
|
|
6146
|
+
const subjectPrefix = `agent.${input.workspaceId}.${input.agentId}`;
|
|
6147
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
6148
|
+
const exp = nowSeconds + ENROLLMENT_BEARER_TTL_SECONDS;
|
|
6149
|
+
const bearer = await signEnrollmentBearer(input.secret, {
|
|
6150
|
+
workspaceId: input.workspaceId,
|
|
6151
|
+
agentId: input.agentId,
|
|
6152
|
+
enrollmentId: input.agentId,
|
|
6153
|
+
credentialGeneration: input.credentialGeneration,
|
|
6154
|
+
subjectPrefix,
|
|
6155
|
+
exp
|
|
6156
|
+
});
|
|
6157
|
+
const natsUrls = settings.selfhostedNatsUrl ? [settings.selfhostedNatsUrl] : [];
|
|
6158
|
+
const relayTokenSecret = resolveRelayTokenSecret(settings);
|
|
6159
|
+
const relayToken = relayTokenSecret ? await signRelayToken(relayTokenSecret, {
|
|
6160
|
+
workspaceId: input.workspaceId,
|
|
6161
|
+
agentId: input.agentId,
|
|
6162
|
+
exp: nowSeconds + RELAY_TOKEN_TTL_SECONDS
|
|
6163
|
+
}) : "";
|
|
6164
|
+
return {
|
|
6165
|
+
agentId: input.agentId,
|
|
6166
|
+
workspaceId: input.workspaceId,
|
|
6167
|
+
bearer,
|
|
6168
|
+
subjectPrefix,
|
|
6169
|
+
natsUrls,
|
|
6170
|
+
// Hand the agent the canonical `/stream` dial base, NOT the raw configured URL.
|
|
6171
|
+
// The agent's relay producer appends only its routing query and assumes the base
|
|
6172
|
+
// already carries the relay's `/stream` route; a path-less base 400s the dial and
|
|
6173
|
+
// makes the terminal/desktop streams unreachable.
|
|
6174
|
+
relayUrl: relayDialBaseFromSettings(settings),
|
|
6175
|
+
relayToken,
|
|
6176
|
+
// M-AUTH closes the placeholder: there is NO per-machine NATS Account creds
|
|
6177
|
+
// file. The agent presents the BEARER as the NATS connect auth-token; the
|
|
6178
|
+
// server's auth-callout responder validates it and mints a workspace-scoped
|
|
6179
|
+
// user JWT. We echo the bearer here so a consumer reading this (vestigial) field
|
|
6180
|
+
// as the connect credential still works — the value IS the bearer.
|
|
6181
|
+
natsAccountCreds: bearer,
|
|
6182
|
+
updatePublicKey: settings.agentUpdatePublicKey ?? "",
|
|
6183
|
+
consentedWholeMachine: true,
|
|
6184
|
+
consentedScreenControl: input.consentedScreenControl
|
|
6185
|
+
};
|
|
6186
|
+
}
|
|
5893
6187
|
|
|
5894
6188
|
// src/mcp/capability-account-readiness.ts
|
|
5895
6189
|
function capabilityAccountReadiness(availableRoutes, bindings) {
|
|
@@ -5905,6 +6199,7 @@ function capabilityAccountReadiness(availableRoutes, bindings) {
|
|
|
5905
6199
|
|
|
5906
6200
|
// src/site-uploads.ts
|
|
5907
6201
|
import { WorkspaceArtifactSourceBundle as WorkspaceArtifactSourceBundle2 } from "@opengeni/contracts";
|
|
6202
|
+
import { retryWhileMissing as retryWhileMissing2 } from "@opengeni/storage";
|
|
5908
6203
|
import {
|
|
5909
6204
|
createWorkspaceArtifactUpload,
|
|
5910
6205
|
getWorkspaceArtifactUpload,
|
|
@@ -6017,7 +6312,12 @@ async function validateSiteSource(storage, key, sizeBytes) {
|
|
|
6017
6312
|
"Editable source JSON must be at most 64 MiB. Exclude dependencies and build output; HTML has a separate storage limit."
|
|
6018
6313
|
);
|
|
6019
6314
|
}
|
|
6020
|
-
const content = await storage.getObjectBytes(key);
|
|
6315
|
+
const content = await retryWhileMissing2(() => storage.getObjectBytes(key));
|
|
6316
|
+
if (!content) {
|
|
6317
|
+
throw new WorkspaceArtifactOperationError(
|
|
6318
|
+
"Site source is not available yet. Retry publication with the same upload."
|
|
6319
|
+
);
|
|
6320
|
+
}
|
|
6021
6321
|
try {
|
|
6022
6322
|
WorkspaceArtifactSourceBundle2.parse(
|
|
6023
6323
|
JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(content.bytes))
|
|
@@ -6110,13 +6410,20 @@ async function freeze(storage, from, to, contentType, optional = false) {
|
|
|
6110
6410
|
}
|
|
6111
6411
|
decoder2.decode();
|
|
6112
6412
|
}
|
|
6113
|
-
await storage.putObjectStreamIfAbsent({
|
|
6413
|
+
const created = await storage.putObjectStreamIfAbsent({
|
|
6114
6414
|
key: to,
|
|
6115
6415
|
contentType,
|
|
6116
6416
|
byteSize: head.ContentLength,
|
|
6117
6417
|
chunks: chunks()
|
|
6118
6418
|
});
|
|
6119
|
-
|
|
6419
|
+
if (created) return head.ContentLength;
|
|
6420
|
+
const stored = await retryWhileMissing2(() => storage.headObject(to));
|
|
6421
|
+
if (!stored || stored.ContentLength === void 0) {
|
|
6422
|
+
throw new WorkspaceArtifactOperationError(
|
|
6423
|
+
"Frozen Site upload is unavailable. Retry publication with the same upload."
|
|
6424
|
+
);
|
|
6425
|
+
}
|
|
6426
|
+
return stored.ContentLength;
|
|
6120
6427
|
}
|
|
6121
6428
|
async function prepareWorkspaceArtifactPublication(deps, grant, input) {
|
|
6122
6429
|
const storage = deps.objectStorage;
|
|
@@ -7700,7 +8007,7 @@ import {
|
|
|
7700
8007
|
recordSandboxFilePublication,
|
|
7701
8008
|
withSessionRlsActorContext as withSessionRlsActorContext5
|
|
7702
8009
|
} from "@opengeni/db";
|
|
7703
|
-
import { retryWhileMissing as
|
|
8010
|
+
import { retryWhileMissing as retryWhileMissing4 } from "@opengeni/storage";
|
|
7704
8011
|
import { HTTPException as HTTPException12 } from "hono/http-exception";
|
|
7705
8012
|
|
|
7706
8013
|
// src/sandbox/channel-a.ts
|
|
@@ -9059,7 +9366,7 @@ import {
|
|
|
9059
9366
|
SessionAuthorizationUnavailableError as SessionAuthorizationUnavailableError3
|
|
9060
9367
|
} from "@opengeni/core";
|
|
9061
9368
|
import { recordWorkspaceUsage, requireLimit } from "@opengeni/core";
|
|
9062
|
-
import { retryWhileMissing as
|
|
9369
|
+
import { retryWhileMissing as retryWhileMissing3 } from "@opengeni/storage";
|
|
9063
9370
|
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
9064
9371
|
|
|
9065
9372
|
// src/mcp/files.ts
|
|
@@ -9161,7 +9468,7 @@ function buildFilesMcpServer(deps, authority) {
|
|
|
9161
9468
|
}
|
|
9162
9469
|
|
|
9163
9470
|
// src/mcp-oauth.ts
|
|
9164
|
-
import { createHash as createHash2, randomBytes as
|
|
9471
|
+
import { createHash as createHash2, randomBytes as randomBytes3 } from "crypto";
|
|
9165
9472
|
import {
|
|
9166
9473
|
MCP_OAUTH_ACCESS_TOKEN_TTL_SECONDS,
|
|
9167
9474
|
MCP_OAUTH_AUTHORIZATION_CODE_TTL_SECONDS,
|
|
@@ -9219,7 +9526,7 @@ function normalizedAddress(value) {
|
|
|
9219
9526
|
|
|
9220
9527
|
// src/workspace-tool-gateway.ts
|
|
9221
9528
|
import { knowledgeContextForGateway } from "@opengeni/core";
|
|
9222
|
-
import { createHash, randomBytes } from "crypto";
|
|
9529
|
+
import { createHash, randomBytes as randomBytes2 } from "crypto";
|
|
9223
9530
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9224
9531
|
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
9225
9532
|
import { withSiteSessionOrigin } from "@opengeni/core";
|
|
@@ -9869,7 +10176,7 @@ async function approveWorkspaceToolGatewayCall(prepared, grant, db, input, issue
|
|
|
9869
10176
|
operation: "approval",
|
|
9870
10177
|
source: preparedCall.entry.source
|
|
9871
10178
|
});
|
|
9872
|
-
const approvalToken = `ogta_${
|
|
10179
|
+
const approvalToken = `ogta_${randomBytes2(32).toString("base64url")}`;
|
|
9873
10180
|
const expiresAt = new Date(Date.now() + 5 * 6e4);
|
|
9874
10181
|
try {
|
|
9875
10182
|
await prepared.reauthorize?.();
|
|
@@ -10501,7 +10808,7 @@ function pkceChallenge(verifier) {
|
|
|
10501
10808
|
return createHash2("sha256").update(verifier, "ascii").digest("base64url");
|
|
10502
10809
|
}
|
|
10503
10810
|
function opaque(prefix) {
|
|
10504
|
-
return `${prefix}${
|
|
10811
|
+
return `${prefix}${randomBytes3(32).toString("base64url")}`;
|
|
10505
10812
|
}
|
|
10506
10813
|
function tokenHash(value) {
|
|
10507
10814
|
return createHash2("sha256").update(value, "utf8").digest("hex");
|
|
@@ -10954,7 +11261,7 @@ function registerFileRoutes(app, deps) {
|
|
|
10954
11261
|
const file2 = await rejectAndCleanObject(409, "file upload has expired", "expired");
|
|
10955
11262
|
return c.json(CompleteFileUploadResponse.parse({ file: file2 }));
|
|
10956
11263
|
}
|
|
10957
|
-
const head = await
|
|
11264
|
+
const head = await retryWhileMissing3(async () => {
|
|
10958
11265
|
if (!await objectStorage.fileExists(upload.file)) return null;
|
|
10959
11266
|
return await objectStorage.headFile(upload.file);
|
|
10960
11267
|
});
|
|
@@ -11086,7 +11393,7 @@ function registerFileRoutes(app, deps) {
|
|
|
11086
11393
|
throw new HTTPException11(409, { message: `generated video is ${retained.file.status}` });
|
|
11087
11394
|
}
|
|
11088
11395
|
const file = generatedVideoFileAsset(retained.file);
|
|
11089
|
-
const videoPresent = await
|
|
11396
|
+
const videoPresent = await retryWhileMissing3(
|
|
11090
11397
|
async () => await objectStorage.fileExists(file) ? true : null
|
|
11091
11398
|
);
|
|
11092
11399
|
if (!videoPresent) {
|
|
@@ -11196,7 +11503,7 @@ function registerFileRoutes(app, deps) {
|
|
|
11196
11503
|
if (file.status !== "ready") {
|
|
11197
11504
|
throw new HTTPException11(409, { message: `file is ${file.status}` });
|
|
11198
11505
|
}
|
|
11199
|
-
const present = await
|
|
11506
|
+
const present = await retryWhileMissing3(
|
|
11200
11507
|
async () => await objectStorage.fileExists(file) ? true : null
|
|
11201
11508
|
);
|
|
11202
11509
|
if (!present) {
|
|
@@ -11270,7 +11577,7 @@ async function serveRetainedArtifactContent(c, objectStorage, artifactId2, file,
|
|
|
11270
11577
|
...range.contentRange ? { "Content-Range": range.contentRange } : {}
|
|
11271
11578
|
};
|
|
11272
11579
|
if (range.kind === "empty") {
|
|
11273
|
-
const present = await
|
|
11580
|
+
const present = await retryWhileMissing3(
|
|
11274
11581
|
async () => await objectStorage.fileExists(file) ? true : null
|
|
11275
11582
|
);
|
|
11276
11583
|
if (!present) {
|
|
@@ -11278,7 +11585,7 @@ async function serveRetainedArtifactContent(c, objectStorage, artifactId2, file,
|
|
|
11278
11585
|
}
|
|
11279
11586
|
return c.body(null, 200, headers);
|
|
11280
11587
|
}
|
|
11281
|
-
const bytes = await
|
|
11588
|
+
const bytes = await retryWhileMissing3(
|
|
11282
11589
|
async () => objectStorage.getFileRange(file, {
|
|
11283
11590
|
start: range.start,
|
|
11284
11591
|
end: range.end
|
|
@@ -11674,6 +11981,14 @@ function sandboxFileContentType(filename) {
|
|
|
11674
11981
|
".jpg": "image/jpeg",
|
|
11675
11982
|
".json": "application/json",
|
|
11676
11983
|
".md": "text/markdown",
|
|
11984
|
+
".mp4": "video/mp4",
|
|
11985
|
+
".webm": "video/webm",
|
|
11986
|
+
".ogv": "video/ogg",
|
|
11987
|
+
".mp3": "audio/mpeg",
|
|
11988
|
+
".m4a": "audio/mp4",
|
|
11989
|
+
".ogg": "audio/ogg",
|
|
11990
|
+
".wav": "audio/wav",
|
|
11991
|
+
".flac": "audio/flac",
|
|
11677
11992
|
".pdf": "application/pdf",
|
|
11678
11993
|
".png": "image/png",
|
|
11679
11994
|
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
@@ -11685,7 +12000,9 @@ function sandboxFileContentType(filename) {
|
|
|
11685
12000
|
}[extension] ?? "application/octet-stream";
|
|
11686
12001
|
}
|
|
11687
12002
|
function sandboxArtifactIdentity(input) {
|
|
11688
|
-
const digest2 = createHash3("sha256").update(
|
|
12003
|
+
const digest2 = createHash3("sha256").update(
|
|
12004
|
+
/^(audio|video)\//.test(sandboxFileContentType(input.path)) ? "opengeni-sandbox-media-artifact-v1\0" : "opengeni-sandbox-file-artifact-v1\0"
|
|
12005
|
+
).update(input.workspaceId).update("\0").update(input.sessionId).update("\0").update(input.path).update("\0").update(input.sha256).digest("hex");
|
|
11689
12006
|
return {
|
|
11690
12007
|
fileId: uuidFromDigest(digest2, 0),
|
|
11691
12008
|
uploadId: uuidFromDigest(digest2, 16)
|
|
@@ -11704,7 +12021,7 @@ function assertSandboxArtifactFile(file, expected) {
|
|
|
11704
12021
|
}
|
|
11705
12022
|
}
|
|
11706
12023
|
async function assertVisibleSandboxArtifact(storage, file) {
|
|
11707
|
-
const head = await
|
|
12024
|
+
const head = await retryWhileMissing4(async () => await storage.headObject(file.objectKey));
|
|
11708
12025
|
assertStoredSandboxArtifact(head, file);
|
|
11709
12026
|
}
|
|
11710
12027
|
function assertStoredSandboxArtifact(head, file) {
|
|
@@ -11834,9 +12151,11 @@ import {
|
|
|
11834
12151
|
getGlobalCatalogOAuthProfile,
|
|
11835
12152
|
listConnectionsMetadata,
|
|
11836
12153
|
loadIntegrationOAuthClient,
|
|
12154
|
+
loadIntegrationOAuthPendingState,
|
|
11837
12155
|
normalizeBearerScheme,
|
|
11838
12156
|
replaceIntegrationOAuthClientIfCurrent,
|
|
11839
12157
|
storeIntegrationOAuthClient,
|
|
12158
|
+
storeIntegrationOAuthPendingState,
|
|
11840
12159
|
updateConnection,
|
|
11841
12160
|
withDatabaseStatementTimeout
|
|
11842
12161
|
} from "@opengeni/db";
|
|
@@ -11854,7 +12173,7 @@ import {
|
|
|
11854
12173
|
validateHttpUrl
|
|
11855
12174
|
} from "@opengeni/network";
|
|
11856
12175
|
import { Buffer as Buffer2 } from "buffer";
|
|
11857
|
-
import { createHash as createHash4, randomBytes as
|
|
12176
|
+
import { createHash as createHash4, randomBytes as randomBytes4, randomUUID } from "crypto";
|
|
11858
12177
|
import { HTTPException as HTTPException17 } from "hono/http-exception";
|
|
11859
12178
|
|
|
11860
12179
|
// src/connection-ownership.ts
|
|
@@ -12406,7 +12725,7 @@ async function startMcpOAuthWithinDeadline(deps, context, deadline) {
|
|
|
12406
12725
|
)
|
|
12407
12726
|
);
|
|
12408
12727
|
const key = requireEnvironmentEncryption(settings);
|
|
12409
|
-
const
|
|
12728
|
+
const fullState = createSignedState3(requireIntegrationsStateSecret(settings), {
|
|
12410
12729
|
...context.integrationKey ? { integrationKey: context.integrationKey } : {},
|
|
12411
12730
|
...context.connectAttemptId ? { connectAttemptId: context.connectAttemptId } : {},
|
|
12412
12731
|
accountId: context.accountId,
|
|
@@ -12448,6 +12767,30 @@ async function startMcpOAuthWithinDeadline(deps, context, deadline) {
|
|
|
12448
12767
|
returnPath,
|
|
12449
12768
|
...existing ? { connectionId: existing.id, connectionVersion: existing.version } : {}
|
|
12450
12769
|
});
|
|
12770
|
+
const expiresAt = new Date(Date.now() + oauthStateTtlMs);
|
|
12771
|
+
let state = fullState;
|
|
12772
|
+
if (settings.integrationsOauthShortStateEnabled) {
|
|
12773
|
+
const stateId = randomUUID();
|
|
12774
|
+
state = createSignedState3(requireIntegrationsStateSecret(settings), {
|
|
12775
|
+
kind: "mcp_oauth_reference",
|
|
12776
|
+
id: stateId,
|
|
12777
|
+
accountId: context.accountId,
|
|
12778
|
+
workspaceId: context.workspaceId
|
|
12779
|
+
});
|
|
12780
|
+
if (state.length > 512) {
|
|
12781
|
+
throw new Error("MCP OAuth reference state exceeded its provider-safe length");
|
|
12782
|
+
}
|
|
12783
|
+
await deadline.run(
|
|
12784
|
+
"state_persist",
|
|
12785
|
+
async () => storeIntegrationOAuthPendingState(db, {
|
|
12786
|
+
id: stateId,
|
|
12787
|
+
accountId: context.accountId,
|
|
12788
|
+
workspaceId: context.workspaceId,
|
|
12789
|
+
stateEncrypted: encryptEnvironmentValue3(key, fullState),
|
|
12790
|
+
expiresAt
|
|
12791
|
+
})
|
|
12792
|
+
);
|
|
12793
|
+
}
|
|
12451
12794
|
const authorizationUrl = buildAuthorizationUrl({
|
|
12452
12795
|
endpoint: discovery.as.authorizationEndpoint,
|
|
12453
12796
|
settings,
|
|
@@ -12463,7 +12806,7 @@ async function startMcpOAuthWithinDeadline(deps, context, deadline) {
|
|
|
12463
12806
|
return OAuthStartResponse.parse({
|
|
12464
12807
|
state,
|
|
12465
12808
|
authorizationUrl,
|
|
12466
|
-
expiresAt:
|
|
12809
|
+
expiresAt: expiresAt.toISOString()
|
|
12467
12810
|
});
|
|
12468
12811
|
}
|
|
12469
12812
|
function assertOAuthStartProfile(settings, payload, mcpUrl, profile) {
|
|
@@ -12519,7 +12862,7 @@ async function completeMcpOAuthCallbackWithinDeadline(deps, input, deadline) {
|
|
|
12519
12862
|
};
|
|
12520
12863
|
}
|
|
12521
12864
|
try {
|
|
12522
|
-
state =
|
|
12865
|
+
state = await resolveMcpOAuthState(db, settings, input.state, deadline);
|
|
12523
12866
|
integrationKey = state.integrationKey ?? "custom:mcp";
|
|
12524
12867
|
if (state.connectAttemptId) {
|
|
12525
12868
|
const stored = await getConnectAttempt2(db, state, state.connectAttemptId);
|
|
@@ -13297,6 +13640,33 @@ function buildAuthorizationUrl(input) {
|
|
|
13297
13640
|
}
|
|
13298
13641
|
return url.toString();
|
|
13299
13642
|
}
|
|
13643
|
+
async function resolveMcpOAuthState(db, settings, state, deadline) {
|
|
13644
|
+
const reference = readSignedState4(state, requireIntegrationsStateSecret(settings));
|
|
13645
|
+
if (reference?.kind !== "mcp_oauth_reference") {
|
|
13646
|
+
return readOAuthState(state, settings);
|
|
13647
|
+
}
|
|
13648
|
+
const accountId = requiredString(reference.accountId, "state.accountId");
|
|
13649
|
+
const workspaceId = requiredString(reference.workspaceId, "state.workspaceId");
|
|
13650
|
+
const id = requiredString(reference.id, "state.id");
|
|
13651
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id)) {
|
|
13652
|
+
throw new HTTPException17(400, { message: "invalid OAuth state reference" });
|
|
13653
|
+
}
|
|
13654
|
+
const encrypted = await runCallbackDatabaseStage(
|
|
13655
|
+
deadline,
|
|
13656
|
+
"state_verify",
|
|
13657
|
+
db,
|
|
13658
|
+
(scopedDb) => loadIntegrationOAuthPendingState(scopedDb, { accountId, workspaceId, id })
|
|
13659
|
+
);
|
|
13660
|
+
if (!encrypted) {
|
|
13661
|
+
throw new HTTPException17(400, { message: "invalid or expired OAuth state" });
|
|
13662
|
+
}
|
|
13663
|
+
const fullState = decryptEnvironmentValue2(requireEnvironmentEncryption(settings), encrypted);
|
|
13664
|
+
const resolved = readOAuthState(fullState, settings);
|
|
13665
|
+
if (resolved.accountId !== accountId || resolved.workspaceId !== workspaceId) {
|
|
13666
|
+
throw new HTTPException17(400, { message: "OAuth state reference mismatch" });
|
|
13667
|
+
}
|
|
13668
|
+
return resolved;
|
|
13669
|
+
}
|
|
13300
13670
|
function readOAuthState(state, settings) {
|
|
13301
13671
|
const payload = readSignedState4(state, requireIntegrationsStateSecret(settings));
|
|
13302
13672
|
if (!payload) {
|
|
@@ -13633,6 +14003,8 @@ function oauthStartStageLabel(stage) {
|
|
|
13633
14003
|
return "authorization-server discovery";
|
|
13634
14004
|
case "client_registration":
|
|
13635
14005
|
return "OAuth client registration";
|
|
14006
|
+
case "state_persist":
|
|
14007
|
+
return "OAuth state persistence";
|
|
13636
14008
|
}
|
|
13637
14009
|
}
|
|
13638
14010
|
function logOAuthVerificationWarning(observability, error, _state) {
|
|
@@ -13920,7 +14292,7 @@ function pkceChallenge2(verifier) {
|
|
|
13920
14292
|
return createHash4("sha256").update(verifier).digest("base64url");
|
|
13921
14293
|
}
|
|
13922
14294
|
function randomPkceVerifier() {
|
|
13923
|
-
return
|
|
14295
|
+
return randomBytes4(32).toString("base64url");
|
|
13924
14296
|
}
|
|
13925
14297
|
function uniqueStrings(values) {
|
|
13926
14298
|
return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
|
|
@@ -13964,7 +14336,7 @@ import {
|
|
|
13964
14336
|
import { createSignedState as createSignedState4, readSignedState as readSignedState5 } from "@opengeni/github";
|
|
13965
14337
|
import { OAUTH_MAX_RESPONSE_BYTES as OAUTH_MAX_RESPONSE_BYTES3, pinnedFetch as pinnedFetch2, readResponseJsonBounded as readResponseJsonBounded2 } from "@opengeni/network";
|
|
13966
14338
|
import { Buffer as Buffer3 } from "buffer";
|
|
13967
|
-
import { createHash as createHash5, randomBytes as
|
|
14339
|
+
import { createHash as createHash5, randomBytes as randomBytes5 } from "crypto";
|
|
13968
14340
|
import { HTTPException as HTTPException18 } from "hono/http-exception";
|
|
13969
14341
|
var SOCIAL_USER_AGENT = "opengeni:social-connector:v0.1.0 (self-hosted)";
|
|
13970
14342
|
var SOCIAL_TIMEOUT_MS = 1e4;
|
|
@@ -14033,7 +14405,7 @@ async function startSocialOAuth(deps, context) {
|
|
|
14033
14405
|
const redirectUri = socialOAuthRedirectUri(settings, context.requestUrl);
|
|
14034
14406
|
const returnPath = safeReturnPath2(context.payload.returnPath ?? "/integrations");
|
|
14035
14407
|
const scopes = uniqueScopes(context.payload.scopes) ?? provider.defaultScopes;
|
|
14036
|
-
const verifier = provider.pkce ?
|
|
14408
|
+
const verifier = provider.pkce ? randomBytes5(32).toString("base64url") : null;
|
|
14037
14409
|
const key = requireEnvironmentEncryption2(settings);
|
|
14038
14410
|
const state = createSignedState4(requireIntegrationsStateSecret(settings), {
|
|
14039
14411
|
kind: "social_oauth",
|
|
@@ -15772,6 +16144,21 @@ function boundRigDetailMcp(rig, versionsPage, changesPage, maxBytes = RIG_DETAIL
|
|
|
15772
16144
|
return result;
|
|
15773
16145
|
}
|
|
15774
16146
|
|
|
16147
|
+
// src/mcp/child-read-evidence.ts
|
|
16148
|
+
function completeChildReadSequences(page) {
|
|
16149
|
+
if (!page.sourceExact || !["conversation", "results"].includes(page.view)) return [];
|
|
16150
|
+
return page.events.filter((event) => {
|
|
16151
|
+
if (event.sourceOmitted) return false;
|
|
16152
|
+
if (event.fragment === void 0) return true;
|
|
16153
|
+
if (!event.fragment || typeof event.fragment !== "object") return false;
|
|
16154
|
+
const fragment = event.fragment;
|
|
16155
|
+
return fragment.offset === 0 && fragment.complete === true;
|
|
16156
|
+
}).map((event) => event.sequence);
|
|
16157
|
+
}
|
|
16158
|
+
|
|
16159
|
+
// src/mcp/server.ts
|
|
16160
|
+
import { acknowledgeConsumedChildEvents } from "@opengeni/db";
|
|
16161
|
+
|
|
15775
16162
|
// src/mcp/session-wait.ts
|
|
15776
16163
|
import {
|
|
15777
16164
|
SESSION_EVENT_SEMANTIC_CLASS_TYPES,
|
|
@@ -16069,6 +16456,7 @@ function summarizeSessionWaitEvent(event, textChars = SUMMARY_TEXT_TIERS[0]) {
|
|
|
16069
16456
|
} else if (typeof compact.result === "string" && compact.result !== compact.text) {
|
|
16070
16457
|
summary.result = clampSummaryString(compact.result, textChars);
|
|
16071
16458
|
}
|
|
16459
|
+
summary.contentComplete = ["turn.completed", "agent.message.completed"].includes(event.type) && !compact.truncation.truncated && text === compact.text && JSON.stringify(failure) === JSON.stringify(compact.failure) && (compact.output === null || compact.output === compact.text || JSON.stringify(compact.output) === JSON.stringify(summary.result)) && (compact.result === null || compact.result === void 0 || compact.result === compact.text || JSON.stringify(summary.result) === JSON.stringify(compact.result));
|
|
16072
16460
|
return summary;
|
|
16073
16461
|
}
|
|
16074
16462
|
function prettyJsonBytes2(value) {
|
|
@@ -16100,6 +16488,7 @@ function boundSessionWaitResult(input, maxBytes = SESSION_EVENT_MCP_MAX_BYTES) {
|
|
|
16100
16488
|
...target,
|
|
16101
16489
|
events: target.events.map((event) => ({
|
|
16102
16490
|
...event,
|
|
16491
|
+
contentComplete: false,
|
|
16103
16492
|
text: event.text === null ? null : clampSummaryString(event.text, textChars),
|
|
16104
16493
|
...typeof event.result === "string" ? { result: clampSummaryString(event.result, textChars) } : {}
|
|
16105
16494
|
}))
|
|
@@ -17543,7 +17932,7 @@ function viewerIdAsUuid(rawViewerId) {
|
|
|
17543
17932
|
}
|
|
17544
17933
|
|
|
17545
17934
|
// src/integrations/slack-bot.ts
|
|
17546
|
-
import { createHmac as createHmac3, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
17935
|
+
import { createHash as createHash7, createHmac as createHmac3, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
17547
17936
|
import { environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes3 } from "@opengeni/config";
|
|
17548
17937
|
import {
|
|
17549
17938
|
OPENGENI_SLACK_BOT_CREDENTIAL_LABEL,
|
|
@@ -18228,6 +18617,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18228
18617
|
const targetKind = input.userId ? "user" : "channel";
|
|
18229
18618
|
const targetId = input.userId ?? input.channelId;
|
|
18230
18619
|
const blocks = validateSlackMessageBlocks(input.blocks);
|
|
18620
|
+
const wireBlocks = slackMessageWireBlocks(blocks);
|
|
18231
18621
|
const requestDigest = this.postRequestDigest({
|
|
18232
18622
|
operationId: input.operationId,
|
|
18233
18623
|
targetKind,
|
|
@@ -18309,7 +18699,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18309
18699
|
const posted = await this.call(headers, "chat.postMessage", {
|
|
18310
18700
|
channel: channelId,
|
|
18311
18701
|
text: input.text,
|
|
18312
|
-
...
|
|
18702
|
+
...wireBlocks ? { blocks: JSON.stringify(wireBlocks) } : {},
|
|
18313
18703
|
client_msg_id: input.operationId,
|
|
18314
18704
|
unfurl_links: "false",
|
|
18315
18705
|
unfurl_media: "false",
|
|
@@ -18367,6 +18757,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18367
18757
|
let providerCallStarted = false;
|
|
18368
18758
|
const blocks = validateSlackMessageBlocks(input.blocks);
|
|
18369
18759
|
try {
|
|
18760
|
+
const wireBlocks = slackMessageWireBlocks(blocks);
|
|
18370
18761
|
const headers = await this.headersFor(operation);
|
|
18371
18762
|
await this.requireMemberChannel(headers, input.channelId);
|
|
18372
18763
|
const requestDigest = this.updateRequestDigest({ ...input, ...blocks ? { blocks } : {} });
|
|
@@ -18405,7 +18796,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18405
18796
|
channel: input.channelId,
|
|
18406
18797
|
ts: input.timestamp,
|
|
18407
18798
|
text: input.text,
|
|
18408
|
-
...
|
|
18799
|
+
...wireBlocks ? { blocks: JSON.stringify(wireBlocks) } : {}
|
|
18409
18800
|
});
|
|
18410
18801
|
const slackChannelId = requiredSlackString(updated.channel, "channel");
|
|
18411
18802
|
const slackMessageTimestamp = requiredSlackString(updated.ts, "ts");
|
|
@@ -19713,6 +20104,20 @@ function nextSlackFilesListPage(payload, requested, returnedFileCount) {
|
|
|
19713
20104
|
}
|
|
19714
20105
|
return nextPage;
|
|
19715
20106
|
}
|
|
20107
|
+
function slackMessageWireBlocks(blocks) {
|
|
20108
|
+
if (!blocks) return void 0;
|
|
20109
|
+
const wire = blocks.flatMap((block, index) => {
|
|
20110
|
+
if (block.type !== "actions" || new Set(block.elements.map((e) => e.action_id)).size === block.elements.length)
|
|
20111
|
+
return [block];
|
|
20112
|
+
const id = createHash7("sha256").update(`${index}:${block.block_id}`).digest("hex").slice(0, 24);
|
|
20113
|
+
return block.elements.map((element, position2) => ({
|
|
20114
|
+
type: "actions",
|
|
20115
|
+
block_id: `opengeni_wire_${id}_${position2}`,
|
|
20116
|
+
elements: [element]
|
|
20117
|
+
}));
|
|
20118
|
+
});
|
|
20119
|
+
return validateSlackMessageBlocks(wire);
|
|
20120
|
+
}
|
|
19716
20121
|
function validateSlackMessageBlocks(blocks) {
|
|
19717
20122
|
if (blocks === void 0) return void 0;
|
|
19718
20123
|
if (blocks.length < 1 || blocks.length > MAX_SLACK_BLOCKS) {
|
|
@@ -19778,7 +20183,7 @@ function slackMutationOutcomeMayBeAmbiguous(error) {
|
|
|
19778
20183
|
|
|
19779
20184
|
// src/integrations/fiken.ts
|
|
19780
20185
|
import { withOrganizationIntegrationAcquisition as withOrganizationIntegrationAcquisition3 } from "@opengeni/db/organization-integration-policy";
|
|
19781
|
-
import { createHash as
|
|
20186
|
+
import { createHash as createHash8 } from "crypto";
|
|
19782
20187
|
import { ExternalActorContinuation as ExternalActorContinuation3 } from "@opengeni/contracts/external-identities";
|
|
19783
20188
|
import { requireConnectOwnerAuthority as requireConnectOwnerAuthority2 } from "@opengeni/core";
|
|
19784
20189
|
import {
|
|
@@ -20599,7 +21004,7 @@ async function completeFikenOAuthCallback(deps, input) {
|
|
|
20599
21004
|
operation = {
|
|
20600
21005
|
attemptId: state.connectAttemptId,
|
|
20601
21006
|
operationId: `oauth:${state.nonce}`,
|
|
20602
|
-
inputDigest:
|
|
21007
|
+
inputDigest: createHash8("sha256").update(input.state).digest("hex")
|
|
20603
21008
|
};
|
|
20604
21009
|
const claim = await claimOAuthAcquisition(
|
|
20605
21010
|
deps.db,
|
|
@@ -20906,7 +21311,7 @@ import {
|
|
|
20906
21311
|
knowledgeSourceAgentConfig,
|
|
20907
21312
|
assertOrganizationIntegrationAllowed as assertOrganizationIntegrationAllowed2
|
|
20908
21313
|
} from "@opengeni/contracts";
|
|
20909
|
-
import { createHash as
|
|
21314
|
+
import { createHash as createHash9 } from "crypto";
|
|
20910
21315
|
import { ExternalActorContinuation as ExternalActorContinuation4 } from "@opengeni/contracts/external-identities";
|
|
20911
21316
|
import {
|
|
20912
21317
|
ATLASSIAN_CREDENTIAL_LABEL,
|
|
@@ -21032,7 +21437,7 @@ async function completeAtlassianOAuthCallback(deps, input) {
|
|
|
21032
21437
|
operation = {
|
|
21033
21438
|
attemptId: state.connectAttemptId,
|
|
21034
21439
|
operationId: `oauth:${state.nonce}`,
|
|
21035
|
-
inputDigest:
|
|
21440
|
+
inputDigest: createHash9("sha256").update(input.state).digest("hex")
|
|
21036
21441
|
};
|
|
21037
21442
|
const claim = await claimOAuthAcquisition(
|
|
21038
21443
|
deps.db,
|
|
@@ -22466,7 +22871,7 @@ function adfText(value) {
|
|
|
22466
22871
|
import { AtlassianConnectionMetadata as AtlassianConnectionMetadata2 } from "@opengeni/contracts/atlassian";
|
|
22467
22872
|
|
|
22468
22873
|
// src/mcp/editable-artifacts.ts
|
|
22469
|
-
import { createHash as
|
|
22874
|
+
import { createHash as createHash10 } from "crypto";
|
|
22470
22875
|
import {
|
|
22471
22876
|
editableArtifactClientTransactionId as editableArtifactClientTransactionId2,
|
|
22472
22877
|
editableArtifactId as editableArtifactId2
|
|
@@ -22889,7 +23294,7 @@ function registerEditableArtifactAgentTools(input) {
|
|
|
22889
23294
|
}
|
|
22890
23295
|
function artifactAttemptContext(grant, sessionId, toolName, extra) {
|
|
22891
23296
|
const operationId = trustedOperationId(extra);
|
|
22892
|
-
const digest2 =
|
|
23297
|
+
const digest2 = createHash10("sha256").update("opengeni:editable-artifact-agent-call:v1\0", "utf8").update(grant.accountId, "utf8").update("\0", "utf8").update(grant.workspaceId, "utf8").update("\0", "utf8").update(sessionId, "utf8").update("\0", "utf8").update(String(grant.metadata?.["turnId"] ?? ""), "utf8").update("\0", "utf8").update(String(grant.metadata?.["attemptId"] ?? ""), "utf8").update("\0", "utf8").update(String(grant.metadata?.["executionGeneration"] ?? ""), "utf8").update("\0", "utf8").update(toolName, "utf8").update("\0", "utf8").update(operationId, "utf8").digest("hex");
|
|
22893
23298
|
const replicaId = digest2.slice(0, 16) === "0".repeat(16) ? `1${digest2.slice(1, 16)}` : digest2.slice(0, 16);
|
|
22894
23299
|
const actor = editableArtifactActorForGrant(grant, replicaId);
|
|
22895
23300
|
if (actor.kind !== "agent" || actor.sessionId !== sessionId) {
|
|
@@ -23095,7 +23500,7 @@ import {
|
|
|
23095
23500
|
knowledgeSourceAgentConfig as knowledgeSourceAgentConfig2,
|
|
23096
23501
|
assertOrganizationIntegrationAllowed as assertOrganizationIntegrationAllowed3
|
|
23097
23502
|
} from "@opengeni/contracts";
|
|
23098
|
-
import { createHash as
|
|
23503
|
+
import { createHash as createHash11, randomBytes as randomBytes6 } from "crypto";
|
|
23099
23504
|
import { ExternalActorContinuation as ExternalActorContinuation5 } from "@opengeni/contracts/external-identities";
|
|
23100
23505
|
import {
|
|
23101
23506
|
configuredGoogleDriveSyncLimits,
|
|
@@ -23216,7 +23621,7 @@ async function startGoogleDriveOAuth(deps, input) {
|
|
|
23216
23621
|
requireGoogleDriveConnection(existing, input.subjectId);
|
|
23217
23622
|
}
|
|
23218
23623
|
const key = requireEnvironmentEncryption5(deps.settings);
|
|
23219
|
-
const verifier =
|
|
23624
|
+
const verifier = randomBytes6(48).toString("base64url");
|
|
23220
23625
|
const redirectUri = requireGoogleDriveOAuthCallbackUrl(deps.settings);
|
|
23221
23626
|
const state = createSignedState7(requireIntegrationsStateSecret(deps.settings), {
|
|
23222
23627
|
accountId: input.accountId,
|
|
@@ -23262,7 +23667,7 @@ async function startGoogleDriveOAuth(deps, input) {
|
|
|
23262
23667
|
authorizationUrl.searchParams.set("code_challenge_method", "S256");
|
|
23263
23668
|
authorizationUrl.searchParams.set(
|
|
23264
23669
|
"code_challenge",
|
|
23265
|
-
|
|
23670
|
+
createHash11("sha256").update(verifier).digest("base64url")
|
|
23266
23671
|
);
|
|
23267
23672
|
return GoogleDriveOAuthStartResponse.parse({
|
|
23268
23673
|
authorizationUrl: authorizationUrl.toString(),
|
|
@@ -23286,7 +23691,7 @@ async function completeGoogleDriveOAuthCallback(deps, input) {
|
|
|
23286
23691
|
operation = {
|
|
23287
23692
|
attemptId: state.connectAttemptId,
|
|
23288
23693
|
operationId: `oauth:${state.nonce}`,
|
|
23289
|
-
inputDigest:
|
|
23694
|
+
inputDigest: createHash11("sha256").update(input.state).digest("hex")
|
|
23290
23695
|
};
|
|
23291
23696
|
const claim = await claimOAuthAcquisition(
|
|
23292
23697
|
deps.db,
|
|
@@ -25206,7 +25611,7 @@ function uniqueStrings3(values) {
|
|
|
25206
25611
|
}
|
|
25207
25612
|
|
|
25208
25613
|
// src/temporal-schedule-cleanup.ts
|
|
25209
|
-
import { randomUUID } from "crypto";
|
|
25614
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
25210
25615
|
import {
|
|
25211
25616
|
claimTemporalScheduleCleanups,
|
|
25212
25617
|
completeTemporalScheduleConnectorCleanup,
|
|
@@ -25278,7 +25683,7 @@ async function processTemporalScheduleCleanupClaims(deps, claims) {
|
|
|
25278
25683
|
}
|
|
25279
25684
|
async function drainTemporalScheduleCleanupOutbox(deps) {
|
|
25280
25685
|
const claims = await claimTemporalScheduleCleanups(deps.db, {
|
|
25281
|
-
claimId:
|
|
25686
|
+
claimId: randomUUID2(),
|
|
25282
25687
|
limit: CLEANUP_BATCH_SIZE,
|
|
25283
25688
|
claimSeconds: CLEANUP_CLAIM_SECONDS
|
|
25284
25689
|
});
|
|
@@ -26627,7 +27032,7 @@ function registerSandboxFileArtifactTool(server, deps, grant, sessionId, json) {
|
|
|
26627
27032
|
server.registerTool(
|
|
26628
27033
|
"sandbox_file_publish",
|
|
26629
27034
|
{
|
|
26630
|
-
description: "Publish one exact file from this session's /workspace into durable workspace storage. Use this before presenting a ZIP, CSV, JSON, Markdown, HTML, PDF, Office file, or other sandbox output as downloadable.
|
|
27035
|
+
description: "Publish one exact file from this session's /workspace into durable workspace storage. Use this before presenting a video, ZIP, CSV, JSON, Markdown, HTML, PDF, Office file, or other sandbox output as downloadable. Present the returned artifact.artifactId as [Open file](artifact:<artifactId>), or  for inline image/video/audio/PDF previews. Replace <artifactId> with the exact returned ID and use a descriptive label. Never expose a sandbox: URL as the durable result.",
|
|
26631
27036
|
inputSchema: {
|
|
26632
27037
|
path: z43.string().min(1).max(4096)
|
|
26633
27038
|
}
|
|
@@ -27369,7 +27774,7 @@ function registerGoalTools(server, deps, grant, sessionId, json) {
|
|
|
27369
27774
|
async ({ reason, timeoutSeconds, idempotencyKey }) => {
|
|
27370
27775
|
await authorizeFirstPartySession(deps, grant, sessionId, "session.control");
|
|
27371
27776
|
const context = exactAgentCommandContext(grant, sessionId);
|
|
27372
|
-
const operationKey = idempotencyKey ?? `wait-for-input:${context.callerTurnId}:${
|
|
27777
|
+
const operationKey = idempotencyKey ?? `wait-for-input:${context.callerTurnId}:${createHash12("sha256").update(JSON.stringify({ reason, timeoutSeconds })).digest("hex").slice(0, 32)}`;
|
|
27373
27778
|
const { events, operationId, replay, deadlineAt } = await waitForSessionInputWithEvent(
|
|
27374
27779
|
deps.db,
|
|
27375
27780
|
grant.workspaceId,
|
|
@@ -27610,7 +28015,7 @@ function registerWorkspaceArtifactTools(server, deps, grant, sessionId, json) {
|
|
|
27610
28015
|
return {
|
|
27611
28016
|
accountId: grant.accountId,
|
|
27612
28017
|
workspaceId: grant.workspaceId,
|
|
27613
|
-
operationKey: `attempt:${
|
|
28018
|
+
operationKey: `attempt:${createHash12("sha256").update(`${claims.sessionId}:${claims.turnId}:${idempotencyKey}`).digest("hex")}`,
|
|
27614
28019
|
actorSubjectId: grant.subjectId,
|
|
27615
28020
|
sourceSessionId: claims.sessionId,
|
|
27616
28021
|
sourceTurnId: claims.turnId,
|
|
@@ -28300,7 +28705,7 @@ function registerFleetTools(server, deps, grant, sessionId, json) {
|
|
|
28300
28705
|
server.registerTool(
|
|
28301
28706
|
"sandbox_provision",
|
|
28302
28707
|
{
|
|
28303
|
-
description: "Provision a new sandbox for the fleet. kind=selfhosted returns device-flow
|
|
28708
|
+
description: "Provision a new sandbox for the fleet. kind=selfhosted returns interactive device-flow instructions for a human to approve. For authorized headless enrollment, use connected_machine_enroll_token when available instead. kind=modal creates a named Modal sandbox record, but it is NOT yet attachable as a swap target: routing a session onto a second Modal box is not supported yet, so sandbox_swap to its id is rejected. Use the session's own box (the default) or attach a Connected Machine instead.",
|
|
28304
28709
|
inputSchema: {
|
|
28305
28710
|
kind: z43.enum(["selfhosted", "modal"]),
|
|
28306
28711
|
name: z43.string().min(1).max(120).optional()
|
|
@@ -28315,10 +28720,38 @@ function registerFleetTools(server, deps, grant, sessionId, json) {
|
|
|
28315
28720
|
);
|
|
28316
28721
|
}
|
|
28317
28722
|
function registerConnectedMachineTools(server, deps, grant, sessionId, json) {
|
|
28723
|
+
server.registerTool(
|
|
28724
|
+
"connected_machine_enroll_token",
|
|
28725
|
+
{
|
|
28726
|
+
description: "Create a short-lived Connected Machine enrollment token for this workspace using existing enrollments:manage authority. Returns the token, expiry and Unix/PowerShell install commands. Run the appropriate command on the intended machine through an already-authorized execution path, then verify it with sandboxes_list. No separate device approval is required. Screen control is optional and defaults off. The token grants whole-machine access on enrollment; do not put it in public code or unrelated logs. Existing machine connections are preserved.",
|
|
28727
|
+
inputSchema: { allowScreenControl: z43.boolean().optional() }
|
|
28728
|
+
},
|
|
28729
|
+
async ({ allowScreenControl }) => {
|
|
28730
|
+
if (sessionId) {
|
|
28731
|
+
await authorizeFirstPartySession(deps, grant, sessionId, "session.first_party_mcp.call");
|
|
28732
|
+
}
|
|
28733
|
+
const minted = await mintEnrollToken(deps, {
|
|
28734
|
+
accountId: grant.accountId,
|
|
28735
|
+
workspaceId: grant.workspaceId,
|
|
28736
|
+
allowScreenControl: allowScreenControl ?? false
|
|
28737
|
+
});
|
|
28738
|
+
if (!minted) throw new Error("enrollment credential plane is not configured");
|
|
28739
|
+
const base = (deps.settings.publicBaseUrl ?? "https://app.opengeni.ai").replace(/\/+$/, "");
|
|
28740
|
+
const unixQuote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
|
|
28741
|
+
const windowsQuote = (value) => `'${value.replaceAll("'", "''")}'`;
|
|
28742
|
+
return json({
|
|
28743
|
+
...minted,
|
|
28744
|
+
workspaceId: grant.workspaceId,
|
|
28745
|
+
allowScreenControl: allowScreenControl ?? false,
|
|
28746
|
+
installCommandUnix: `curl -fsSL ${unixQuote(`${base}/install.sh`)} | OPENGENI_API_URL=${unixQuote(base)} OPENGENI_ENROLL_TOKEN=${unixQuote(minted.token)} sh`,
|
|
28747
|
+
installCommandWindows: `$env:OPENGENI_API_URL=${windowsQuote(base)}; $env:OPENGENI_ENROLL_TOKEN=${windowsQuote(minted.token)}; irm ${windowsQuote(`${base}/install.ps1`)} | iex`
|
|
28748
|
+
});
|
|
28749
|
+
}
|
|
28750
|
+
);
|
|
28318
28751
|
server.registerTool(
|
|
28319
28752
|
"connected_machine_remove",
|
|
28320
28753
|
{
|
|
28321
|
-
description: "Remove one enrolled self-hosted machine while it is offline. Access is revoked, future heartbeat/reconnect credentials are rejected, and session, route, lease, archive, and audit history is retained. Idle dependent sessions are detached atomically; machine-home sessions become compute-less (backend none) until another sandbox is selected. Active turns, live leases, and recovery work remain fail-closed blockers whose typed outcome explains what must settle before retrying. Pass the enrollmentId from the Machines surface, never a Modal sandbox id. Reconnecting later requires
|
|
28754
|
+
description: "Remove one enrolled self-hosted machine while it is offline. Access is revoked, future heartbeat/reconnect credentials are rejected, and session, route, lease, archive, and audit history is retained. Idle dependent sessions are detached atomically; machine-home sessions become compute-less (backend none) until another sandbox is selected. Active turns, live leases, and recovery work remain fail-closed blockers whose typed outcome explains what must settle before retrying. Pass the enrollmentId from the Machines surface, never a Modal sandbox id. Reconnecting later requires fresh enrollment through device approval or an authorized enrollment token.",
|
|
28322
28755
|
inputSchema: {
|
|
28323
28756
|
enrollmentId: z43.string().uuid(),
|
|
28324
28757
|
expectedUpdatedAt: z43.string().datetime({ offset: true }).optional(),
|
|
@@ -28343,7 +28776,7 @@ function registerConnectedMachineTools(server, deps, grant, sessionId, json) {
|
|
|
28343
28776
|
accountId: grant.accountId,
|
|
28344
28777
|
workspaceId: enrollment.workspaceId,
|
|
28345
28778
|
enrollmentId,
|
|
28346
|
-
operationKey: idempotencyKey?.trim() ||
|
|
28779
|
+
operationKey: idempotencyKey?.trim() || randomUUID3(),
|
|
28347
28780
|
...expectedUpdatedAt ? { expectedUpdatedAt } : {},
|
|
28348
28781
|
subjectId: resourceGrant.subjectId
|
|
28349
28782
|
});
|
|
@@ -28671,6 +29104,18 @@ function exactAgentCommandContext(grant, callerSessionId, authorizationSurface)
|
|
|
28671
29104
|
};
|
|
28672
29105
|
}
|
|
28673
29106
|
function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSessionId, sessionCreateVisible, json) {
|
|
29107
|
+
const acknowledgeReads = async (children) => {
|
|
29108
|
+
if (!callerSessionId || !exactAgentAttemptClaims(grant) || !children.some((child) => child.sequences.length > 0))
|
|
29109
|
+
return;
|
|
29110
|
+
const actor = await requireLiveAgentAttemptAuthorization4(deps.db, grant, callerSessionId);
|
|
29111
|
+
if (!actor.initiatingHumanSubjectId) return;
|
|
29112
|
+
await acknowledgeConsumedChildEvents(deps.db, {
|
|
29113
|
+
workspaceId: grant.workspaceId,
|
|
29114
|
+
sessionId: callerSessionId,
|
|
29115
|
+
subjectId: actor.initiatingHumanSubjectId,
|
|
29116
|
+
children
|
|
29117
|
+
});
|
|
29118
|
+
};
|
|
28674
29119
|
if (can("sessions:read")) {
|
|
28675
29120
|
server.registerTool(
|
|
28676
29121
|
"sessions_list",
|
|
@@ -28965,29 +29410,29 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
28965
29410
|
if (view !== "debug" && !auditRequested) {
|
|
28966
29411
|
const { readSessionEventView } = await import("./session-event-view-MU3HMNV3.js");
|
|
28967
29412
|
const { listSessionEventSlices } = await import("@opengeni/db/session-event-slices");
|
|
28968
|
-
|
|
28969
|
-
|
|
28970
|
-
|
|
28971
|
-
|
|
28972
|
-
|
|
28973
|
-
|
|
28974
|
-
|
|
28975
|
-
|
|
28976
|
-
|
|
28977
|
-
|
|
28978
|
-
|
|
28979
|
-
|
|
28980
|
-
|
|
28981
|
-
|
|
28982
|
-
|
|
28983
|
-
|
|
28984
|
-
|
|
28985
|
-
|
|
28986
|
-
|
|
28987
|
-
(legacyOptions) => listSessionEventPage(deps.db, grant.workspaceId, sessionId, legacyOptions)
|
|
28988
|
-
)
|
|
29413
|
+
const page2 = await readSessionEventView(
|
|
29414
|
+
{
|
|
29415
|
+
sessionId,
|
|
29416
|
+
view,
|
|
29417
|
+
cursor,
|
|
29418
|
+
callId,
|
|
29419
|
+
includeArguments,
|
|
29420
|
+
includeOutput,
|
|
29421
|
+
after,
|
|
29422
|
+
before,
|
|
29423
|
+
direction: requestedDirection,
|
|
29424
|
+
limit
|
|
29425
|
+
},
|
|
29426
|
+
(options) => listSessionEventSlices(
|
|
29427
|
+
deps.db,
|
|
29428
|
+
grant.workspaceId,
|
|
29429
|
+
sessionId,
|
|
29430
|
+
options,
|
|
29431
|
+
(legacyOptions) => listSessionEventPage(deps.db, grant.workspaceId, sessionId, legacyOptions)
|
|
28989
29432
|
)
|
|
28990
29433
|
);
|
|
29434
|
+
await acknowledgeReads([{ sessionId, sequences: completeChildReadSequences(page2) }]);
|
|
29435
|
+
return json(page2);
|
|
28991
29436
|
}
|
|
28992
29437
|
if (cursor !== void 0 || callId !== void 0 || includeArguments !== void 0 || includeOutput !== void 0) {
|
|
28993
29438
|
throw new Error("cursor/callId/includeArguments/includeOutput require a non-debug view");
|
|
@@ -29017,31 +29462,37 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29017
29462
|
});
|
|
29018
29463
|
if (requestedResultMode === "compact") {
|
|
29019
29464
|
const event = dbPage.events[0];
|
|
29020
|
-
|
|
29021
|
-
|
|
29022
|
-
|
|
29023
|
-
|
|
29024
|
-
|
|
29025
|
-
|
|
29026
|
-
|
|
29027
|
-
|
|
29028
|
-
|
|
29029
|
-
|
|
29030
|
-
|
|
29031
|
-
|
|
29465
|
+
const result = event ? boundSessionEventCompactResult(
|
|
29466
|
+
compactSessionEventResult2(
|
|
29467
|
+
event,
|
|
29468
|
+
latestClass,
|
|
29469
|
+
dbPage.coveredSequence ?? {
|
|
29470
|
+
first: event.sequence,
|
|
29471
|
+
last: event.sequence
|
|
29472
|
+
}
|
|
29473
|
+
)
|
|
29474
|
+
) : null;
|
|
29475
|
+
if (result && ["turn.completed", "agent.message.completed"].includes(result.type) && !result.truncation.truncated && dbPage.fullPayloadsExact) {
|
|
29476
|
+
await acknowledgeReads([{ sessionId, sequences: [result.sequence] }]);
|
|
29477
|
+
}
|
|
29478
|
+
return json(result);
|
|
29032
29479
|
}
|
|
29033
|
-
|
|
29034
|
-
|
|
29035
|
-
|
|
29036
|
-
|
|
29037
|
-
|
|
29038
|
-
|
|
29039
|
-
|
|
29040
|
-
|
|
29041
|
-
|
|
29042
|
-
|
|
29043
|
-
|
|
29044
|
-
|
|
29480
|
+
const page = boundSessionEventMcpPage({
|
|
29481
|
+
events: dbPage.events,
|
|
29482
|
+
mode,
|
|
29483
|
+
payloadMode,
|
|
29484
|
+
direction,
|
|
29485
|
+
sourceHasMore: dbPage.hasMore,
|
|
29486
|
+
sourceTruncatedBy: dbPage.truncatedBy,
|
|
29487
|
+
after: after ?? 0,
|
|
29488
|
+
before: before ?? null
|
|
29489
|
+
});
|
|
29490
|
+
if (payloadMode === "full" && dbPage.fullPayloadsExact && !page.truncation?.reasons.includes("model_payload")) {
|
|
29491
|
+
await acknowledgeReads([
|
|
29492
|
+
{ sessionId, sequences: page.events.map((event) => event.sequence) }
|
|
29493
|
+
]);
|
|
29494
|
+
}
|
|
29495
|
+
return json(page);
|
|
29045
29496
|
}
|
|
29046
29497
|
);
|
|
29047
29498
|
server.registerTool(
|
|
@@ -29077,45 +29528,52 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29077
29528
|
const targetEventTypes = waitFor === "completion" ? SESSION_WAIT_COMPLETION_EVENT_TYPES : SESSION_WAIT_EVENT_TYPES;
|
|
29078
29529
|
const signal = extra?.signal;
|
|
29079
29530
|
const workspaceId = grant.workspaceId;
|
|
29080
|
-
|
|
29081
|
-
|
|
29082
|
-
|
|
29083
|
-
|
|
29084
|
-
|
|
29085
|
-
|
|
29086
|
-
|
|
29087
|
-
|
|
29088
|
-
|
|
29089
|
-
|
|
29090
|
-
|
|
29091
|
-
|
|
29092
|
-
|
|
29093
|
-
|
|
29094
|
-
|
|
29095
|
-
|
|
29096
|
-
|
|
29097
|
-
|
|
29098
|
-
|
|
29099
|
-
|
|
29100
|
-
|
|
29101
|
-
|
|
29102
|
-
|
|
29103
|
-
|
|
29104
|
-
|
|
29105
|
-
|
|
29106
|
-
|
|
29107
|
-
|
|
29108
|
-
|
|
29109
|
-
|
|
29110
|
-
|
|
29111
|
-
|
|
29112
|
-
|
|
29113
|
-
|
|
29114
|
-
|
|
29115
|
-
|
|
29116
|
-
|
|
29117
|
-
|
|
29118
|
-
|
|
29531
|
+
const incompleteWaitEvents = /* @__PURE__ */ new Set();
|
|
29532
|
+
const result = await waitForSessionChanges({
|
|
29533
|
+
targets,
|
|
29534
|
+
ownSessionId,
|
|
29535
|
+
maxWaitMs: (maxWaitSeconds ?? SESSION_WAIT_DEFAULT_SECONDS) * 1e3,
|
|
29536
|
+
targetEventTypes,
|
|
29537
|
+
targetEventMatches: waitFor === "completion" ? sessionWaitCompletionEventMatches : void 0,
|
|
29538
|
+
signal,
|
|
29539
|
+
source: {
|
|
29540
|
+
reauthorizeTargets: async (sessionIds) => {
|
|
29541
|
+
for (const targetSessionId of sessionIds) {
|
|
29542
|
+
await authorizeFirstPartySession(
|
|
29543
|
+
deps,
|
|
29544
|
+
grant,
|
|
29545
|
+
targetSessionId,
|
|
29546
|
+
"session.events.read"
|
|
29547
|
+
);
|
|
29548
|
+
}
|
|
29549
|
+
},
|
|
29550
|
+
readTargetEvents: async (target) => {
|
|
29551
|
+
const page = await listSessionEventPage(deps.db, workspaceId, target.sessionId, {
|
|
29552
|
+
after: target.afterSequence,
|
|
29553
|
+
direction: "after",
|
|
29554
|
+
limit: SESSION_WAIT_EVENTS_PER_TARGET,
|
|
29555
|
+
payloadMode: "full",
|
|
29556
|
+
includeTypes: targetEventTypes,
|
|
29557
|
+
maxBytes: SESSION_EVENT_MCP_MAX_BYTES * 4
|
|
29558
|
+
});
|
|
29559
|
+
if (!page.fullPayloadsExact) {
|
|
29560
|
+
for (const event of page.events) incompleteWaitEvents.add(event.id);
|
|
29561
|
+
}
|
|
29562
|
+
return { events: page.events, hasMore: page.hasMore };
|
|
29563
|
+
},
|
|
29564
|
+
readOwnPendingUpdateKinds: ownSessionId === null ? null : async () => (await listOutstandingSessionSystemUpdates(deps.db, workspaceId, ownSessionId)).map((update) => update.kind),
|
|
29565
|
+
subscribe: (targetSessionId, onEvents) => deps.bus.subscribe(workspaceId, targetSessionId, onEvents)
|
|
29566
|
+
}
|
|
29567
|
+
});
|
|
29568
|
+
if (!result.aborted && !result.truncated) {
|
|
29569
|
+
await acknowledgeReads(
|
|
29570
|
+
result.changed.map((target) => ({
|
|
29571
|
+
sessionId: target.sessionId,
|
|
29572
|
+
sequences: target.events.filter((event) => event.contentComplete && !incompleteWaitEvents.has(event.id)).map((event) => event.sequence)
|
|
29573
|
+
}))
|
|
29574
|
+
);
|
|
29575
|
+
}
|
|
29576
|
+
return json(result);
|
|
29119
29577
|
}
|
|
29120
29578
|
);
|
|
29121
29579
|
if (callerSessionId !== null) {
|
|
@@ -60552,7 +61010,7 @@ function registerOrganizationIntegrationPolicyRoutes(app, deps) {
|
|
|
60552
61010
|
}
|
|
60553
61011
|
|
|
60554
61012
|
// src/routes/connections.ts
|
|
60555
|
-
import { createHash as
|
|
61013
|
+
import { createHash as createHash15, createHmac as createHmac4 } from "crypto";
|
|
60556
61014
|
import {
|
|
60557
61015
|
createConnectionIdempotently,
|
|
60558
61016
|
getConnectionCreationResult,
|
|
@@ -60721,7 +61179,7 @@ import { HTTPException as HTTPException35 } from "hono/http-exception";
|
|
|
60721
61179
|
// src/integrations/provider-oauth.ts
|
|
60722
61180
|
import { withOrganizationIntegrationAcquisition as withOrganizationIntegrationAcquisition6 } from "@opengeni/db/organization-integration-policy";
|
|
60723
61181
|
import { Buffer as Buffer4 } from "buffer";
|
|
60724
|
-
import { createHash as
|
|
61182
|
+
import { createHash as createHash13, randomBytes as randomBytes7 } from "crypto";
|
|
60725
61183
|
import {
|
|
60726
61184
|
integrationDefinitionProviderDomain as integrationDefinitionProviderDomain2,
|
|
60727
61185
|
integrationDefinitionById
|
|
@@ -60804,7 +61262,7 @@ async function startApiIntegrationProviderOAuth(deps, input) {
|
|
|
60804
61262
|
...definition.authentication.scopes
|
|
60805
61263
|
]);
|
|
60806
61264
|
const client = providerClientForDefinition(deps.settings, definition);
|
|
60807
|
-
const verifier =
|
|
61265
|
+
const verifier = randomBytes7(48).toString("base64url");
|
|
60808
61266
|
const key = requireEnvironmentEncryption8(deps.settings);
|
|
60809
61267
|
const baseUrl = integrationBaseUrl(deps.settings.publicBaseUrl, input.requestUrl);
|
|
60810
61268
|
const redirectUri = `${baseUrl}${providerOAuthCallbackPath(definition)}`;
|
|
@@ -60849,7 +61307,7 @@ async function startApiIntegrationProviderOAuth(deps, input) {
|
|
|
60849
61307
|
authorizationUrl.searchParams.set("code_challenge_method", "S256");
|
|
60850
61308
|
authorizationUrl.searchParams.set(
|
|
60851
61309
|
"code_challenge",
|
|
60852
|
-
|
|
61310
|
+
createHash13("sha256").update(verifier).digest("base64url")
|
|
60853
61311
|
);
|
|
60854
61312
|
authorizationUrl.searchParams.set("prompt", "select_account");
|
|
60855
61313
|
if (definition.provider.id === "google") {
|
|
@@ -60879,7 +61337,7 @@ async function completeApiIntegrationProviderOAuth(deps, input) {
|
|
|
60879
61337
|
connectOperation = {
|
|
60880
61338
|
attemptId: state.connectAttemptId,
|
|
60881
61339
|
operationId: `oauth:${state.nonce}`,
|
|
60882
|
-
inputDigest:
|
|
61340
|
+
inputDigest: createHash13("sha256").update(input.state).digest("hex")
|
|
60883
61341
|
};
|
|
60884
61342
|
const claim = await claimOAuthAcquisition(
|
|
60885
61343
|
deps.db,
|
|
@@ -61172,7 +61630,7 @@ function providerClientKeys(definition) {
|
|
|
61172
61630
|
]);
|
|
61173
61631
|
}
|
|
61174
61632
|
function providerDefinitionFingerprint(definition) {
|
|
61175
|
-
return
|
|
61633
|
+
return createHash13("sha256").update(
|
|
61176
61634
|
JSON.stringify({
|
|
61177
61635
|
id: definition.id,
|
|
61178
61636
|
provider: definition.provider,
|
|
@@ -61425,7 +61883,7 @@ function numberValue4(value) {
|
|
|
61425
61883
|
|
|
61426
61884
|
// src/integrations/personal-github.ts
|
|
61427
61885
|
import { withOrganizationIntegrationAcquisition as withOrganizationIntegrationAcquisition7 } from "@opengeni/db/organization-integration-policy";
|
|
61428
|
-
import { createHash as
|
|
61886
|
+
import { createHash as createHash14, randomBytes as randomBytes8, randomUUID as randomUUID4 } from "crypto";
|
|
61429
61887
|
import { ExternalActorContinuation as ExternalActorContinuation8 } from "@opengeni/contracts/external-identities";
|
|
61430
61888
|
import { personalGitHubOAuthCallbackUrl } from "@opengeni/config";
|
|
61431
61889
|
import {
|
|
@@ -61472,7 +61930,7 @@ var PersonalGitHubCallbackError = class extends Error {
|
|
|
61472
61930
|
}
|
|
61473
61931
|
};
|
|
61474
61932
|
function personalGitHubClientMarker(clientId) {
|
|
61475
|
-
return
|
|
61933
|
+
return createHash14("sha256").update(clientId).digest("hex").slice(0, 32);
|
|
61476
61934
|
}
|
|
61477
61935
|
function requirePersonalGitHubOAuthSettings(settings) {
|
|
61478
61936
|
if (!settings.githubPersonalOauthEnabled) {
|
|
@@ -61555,7 +62013,7 @@ async function startPersonalGitHubOAuth(deps, input) {
|
|
|
61555
62013
|
});
|
|
61556
62014
|
}
|
|
61557
62015
|
const key = requireEnvironmentEncryption9(deps.settings);
|
|
61558
|
-
const verifier =
|
|
62016
|
+
const verifier = randomBytes8(48).toString("base64url");
|
|
61559
62017
|
const returnPath = personalGitHubReturnPath(input.workspaceId, input.returnPath);
|
|
61560
62018
|
const state = createSignedState11(requireIntegrationsStateSecret(deps.settings), {
|
|
61561
62019
|
accountId: grant.accountId,
|
|
@@ -61584,7 +62042,7 @@ async function startPersonalGitHubOAuth(deps, input) {
|
|
|
61584
62042
|
authorizationUrl.searchParams.set("state", state);
|
|
61585
62043
|
authorizationUrl.searchParams.set(
|
|
61586
62044
|
"code_challenge",
|
|
61587
|
-
|
|
62045
|
+
createHash14("sha256").update(verifier).digest("base64url")
|
|
61588
62046
|
);
|
|
61589
62047
|
authorizationUrl.searchParams.set("code_challenge_method", "S256");
|
|
61590
62048
|
return PersonalGitHubOAuthStartResponse.parse({
|
|
@@ -61608,7 +62066,7 @@ async function completePersonalGitHubOAuthCallback(deps, input) {
|
|
|
61608
62066
|
operation = {
|
|
61609
62067
|
attemptId: state.connectAttemptId,
|
|
61610
62068
|
operationId: `oauth:${state.nonce}`,
|
|
61611
|
-
inputDigest:
|
|
62069
|
+
inputDigest: createHash14("sha256").update(input.state).digest("hex")
|
|
61612
62070
|
};
|
|
61613
62071
|
const claim = await claimOAuthAcquisition(
|
|
61614
62072
|
deps.db,
|
|
@@ -61710,7 +62168,7 @@ async function completePersonalGitHubOAuthCallback(deps, input) {
|
|
|
61710
62168
|
githubLogin: identity2.login,
|
|
61711
62169
|
oauthEnvironment: oauth.oauthEnvironment,
|
|
61712
62170
|
oauthClientMarker: oauth.oauthClientMarker,
|
|
61713
|
-
credentialBindingId: requestedMetadata?.credentialBindingId ??
|
|
62171
|
+
credentialBindingId: requestedMetadata?.credentialBindingId ?? randomUUID4(),
|
|
61714
62172
|
connectedAt: requestedMetadata?.connectedAt ?? now,
|
|
61715
62173
|
lastVerifiedAt: now,
|
|
61716
62174
|
disconnectedAt: null,
|
|
@@ -62255,7 +62713,7 @@ function registerConnectionRoutes(app, deps) {
|
|
|
62255
62713
|
operation = {
|
|
62256
62714
|
attemptId: state.connectAttemptId,
|
|
62257
62715
|
operationId: `oauth:${state.nonce}`,
|
|
62258
|
-
inputDigest:
|
|
62716
|
+
inputDigest: createHash15("sha256").update(c.req.query("state")).digest("hex")
|
|
62259
62717
|
};
|
|
62260
62718
|
const callbackState = state;
|
|
62261
62719
|
const callbackOperation = operation;
|
|
@@ -62414,7 +62872,7 @@ function registerConnectionRoutes(app, deps) {
|
|
|
62414
62872
|
accountId: state.accountId,
|
|
62415
62873
|
workspaceId: state.workspaceId,
|
|
62416
62874
|
subjectId: state.subjectId,
|
|
62417
|
-
callbackDigest:
|
|
62875
|
+
callbackDigest: createHash15("sha256").update(state.nonce).digest("hex"),
|
|
62418
62876
|
installMode: state.connectionId ? "reinstall" : "connect",
|
|
62419
62877
|
...failure
|
|
62420
62878
|
});
|
|
@@ -63445,7 +63903,7 @@ function slackBotCredentialBundle(token) {
|
|
|
63445
63903
|
}
|
|
63446
63904
|
|
|
63447
63905
|
// src/routes/connect.ts
|
|
63448
|
-
import { createHash as
|
|
63906
|
+
import { createHash as createHash18, createHmac as createHmac5, randomUUID as randomUUID5 } from "crypto";
|
|
63449
63907
|
import { HTTPException as HTTPException39 } from "hono/http-exception";
|
|
63450
63908
|
import { getConnectBeginReplay } from "@opengeni/db/connect-attempts";
|
|
63451
63909
|
import {
|
|
@@ -63496,7 +63954,7 @@ import {
|
|
|
63496
63954
|
} from "@opengeni/core";
|
|
63497
63955
|
|
|
63498
63956
|
// src/integrations/github-app-connect.ts
|
|
63499
|
-
import { createHash as
|
|
63957
|
+
import { createHash as createHash16 } from "crypto";
|
|
63500
63958
|
import { z as z19 } from "zod";
|
|
63501
63959
|
import { HTTPException as HTTPException37 } from "hono/http-exception";
|
|
63502
63960
|
import {
|
|
@@ -63705,7 +64163,7 @@ async function completeGitHubAppConnect(deps, input) {
|
|
|
63705
64163
|
const operation = {
|
|
63706
64164
|
attemptId: state.connectAttemptId,
|
|
63707
64165
|
operationId: `github:${state.nonce}`,
|
|
63708
|
-
inputDigest:
|
|
64166
|
+
inputDigest: createHash16("sha256").update(input.state).digest("hex"),
|
|
63709
64167
|
authorize
|
|
63710
64168
|
};
|
|
63711
64169
|
const claim = await claimOAuthAcquisition(
|
|
@@ -63956,7 +64414,7 @@ import {
|
|
|
63956
64414
|
import { HTTPException as HTTPException38 } from "hono/http-exception";
|
|
63957
64415
|
|
|
63958
64416
|
// src/integrations/api-integrations.ts
|
|
63959
|
-
import { createHash as
|
|
64417
|
+
import { createHash as createHash17 } from "crypto";
|
|
63960
64418
|
import {
|
|
63961
64419
|
compileGraphqlRevision,
|
|
63962
64420
|
compileOpenApiRevision,
|
|
@@ -64175,7 +64633,7 @@ function resolvedPreview(input) {
|
|
|
64175
64633
|
};
|
|
64176
64634
|
}
|
|
64177
64635
|
function integrationInstallationIdentity(protocol, label, locator2) {
|
|
64178
|
-
const hash =
|
|
64636
|
+
const hash = createHash17("sha256").update(`${protocol}\0${locator2}`).digest("hex").slice(0, 12);
|
|
64179
64637
|
const slug = label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48) || "integration";
|
|
64180
64638
|
return {
|
|
64181
64639
|
sourceDerivedDefinitionId: `${slug}-${hash}`,
|
|
@@ -65000,7 +65458,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65000
65458
|
attemptId: before.id,
|
|
65001
65459
|
expectedRevision: input.expectedRevision,
|
|
65002
65460
|
operationId: input.idempotencyKey,
|
|
65003
|
-
inputDigest:
|
|
65461
|
+
inputDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65004
65462
|
authorize: (tx, _attempt, origin) => requireConnectOwnerAuthority(tx, scope, "capabilities:manage", origin),
|
|
65005
65463
|
execute: async (attempt) => {
|
|
65006
65464
|
if (attempt.state !== "credential_input")
|
|
@@ -65042,7 +65500,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65042
65500
|
attemptId: before.id,
|
|
65043
65501
|
expectedRevision: input.expectedRevision,
|
|
65044
65502
|
operationId: input.idempotencyKey,
|
|
65045
|
-
inputDigest:
|
|
65503
|
+
inputDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65046
65504
|
authorize: async (tx, _attempt, origin) => {
|
|
65047
65505
|
await requireConnectOwnerAuthority(tx, scope, installationPermission, origin);
|
|
65048
65506
|
if (before.providerId === "github-lens") {
|
|
@@ -65068,7 +65526,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65068
65526
|
attemptId: before.id,
|
|
65069
65527
|
expectedRevision: input.expectedRevision,
|
|
65070
65528
|
operationId: input.idempotencyKey,
|
|
65071
|
-
inputDigest:
|
|
65529
|
+
inputDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65072
65530
|
authorize: (tx, _attempt, origin) => requireConnectOwnerAuthority(tx, scope, "connections:write", origin),
|
|
65073
65531
|
execute: async (attempt) => {
|
|
65074
65532
|
if (attempt.state !== "credential_input")
|
|
@@ -65367,7 +65825,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65367
65825
|
attemptId: c.req.param("attemptId"),
|
|
65368
65826
|
expectedRevision: input.expectedRevision,
|
|
65369
65827
|
operationId: input.idempotencyKey,
|
|
65370
|
-
inputDigest:
|
|
65828
|
+
inputDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65371
65829
|
authorize: (tx, _attempt, origin) => requireConnectOwnerAuthority(tx, scope, permission, origin),
|
|
65372
65830
|
execute: async (attempt) => {
|
|
65373
65831
|
if (!attempt.source && (!attempt.credentialsCommitted || !attempt.account) || !["connected_but_incomplete", "preview"].includes(attempt.state))
|
|
@@ -65475,7 +65933,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65475
65933
|
attemptId: c.req.param("attemptId"),
|
|
65476
65934
|
expectedRevision: input.expectedRevision,
|
|
65477
65935
|
operationId: input.idempotencyKey,
|
|
65478
|
-
inputDigest:
|
|
65936
|
+
inputDigest: createHash18("sha256").update(stableJson4({ ...input, action: "cancel" })).digest("hex"),
|
|
65479
65937
|
purpose: "cancellation",
|
|
65480
65938
|
authorize: async (tx, attempt, origin) => {
|
|
65481
65939
|
const permission = attempt.providerId === "mcp-install" ? "capabilities:manage" : ["x", "reddit"].includes(attempt.providerId) ? attempt.ownership === "workspace" ? "workspace:admin" : "workspace:read" : attempt.providerId === "github-app" ? "github:manage" : attempt.providerId === "github-lens" ? "workspace:admin" : "connections:write";
|
|
@@ -65540,7 +65998,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65540
65998
|
await requireConnectOwnerAuthority(actorTx, scope, setupPermission);
|
|
65541
65999
|
const replay2 = await getConnectBeginReplay(actorTx, scope, {
|
|
65542
66000
|
idempotencyKey: input.idempotencyKey,
|
|
65543
|
-
requestDigest:
|
|
66001
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65544
66002
|
returnUrl: input.returnUrl,
|
|
65545
66003
|
...continuation ? { externalContinuation: continuation } : {}
|
|
65546
66004
|
});
|
|
@@ -65574,7 +66032,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65574
66032
|
}
|
|
65575
66033
|
);
|
|
65576
66034
|
});
|
|
65577
|
-
const id =
|
|
66035
|
+
const id = randomUUID5();
|
|
65578
66036
|
if (input.providerId === "mcp-install") {
|
|
65579
66037
|
if (input.ownership !== "workspace" || input.reconnectAccountId || input.installationTarget)
|
|
65580
66038
|
throw new HTTPException39(422, {
|
|
@@ -65596,7 +66054,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65596
66054
|
return beginConnectAttempt(tx, scope, {
|
|
65597
66055
|
...continuation ? { externalContinuation: continuation } : {},
|
|
65598
66056
|
idempotencyKey: input.idempotencyKey,
|
|
65599
|
-
requestDigest:
|
|
66057
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65600
66058
|
returnUrl: input.returnUrl,
|
|
65601
66059
|
attempt: {
|
|
65602
66060
|
id,
|
|
@@ -65654,7 +66112,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65654
66112
|
return beginConnectAttempt(tx, scope, {
|
|
65655
66113
|
...continuation ? { externalContinuation: continuation } : {},
|
|
65656
66114
|
idempotencyKey: input.idempotencyKey,
|
|
65657
|
-
requestDigest:
|
|
66115
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65658
66116
|
returnUrl: input.returnUrl,
|
|
65659
66117
|
attempt: {
|
|
65660
66118
|
id,
|
|
@@ -65704,7 +66162,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65704
66162
|
return beginConnectAttempt(tx, scope, {
|
|
65705
66163
|
...continuation ? { externalContinuation: continuation } : {},
|
|
65706
66164
|
idempotencyKey: input.idempotencyKey,
|
|
65707
|
-
requestDigest:
|
|
66165
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65708
66166
|
returnUrl: input.returnUrl,
|
|
65709
66167
|
attempt: {
|
|
65710
66168
|
id,
|
|
@@ -65739,7 +66197,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65739
66197
|
return beginConnectAttempt(tx, scope, {
|
|
65740
66198
|
...continuation ? { externalContinuation: continuation } : {},
|
|
65741
66199
|
idempotencyKey: input.idempotencyKey,
|
|
65742
|
-
requestDigest:
|
|
66200
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65743
66201
|
returnUrl: input.returnUrl,
|
|
65744
66202
|
attempt: {
|
|
65745
66203
|
id,
|
|
@@ -65820,7 +66278,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65820
66278
|
return beginConnectAttempt(tx, scope, {
|
|
65821
66279
|
...continuation ? { externalContinuation: continuation } : {},
|
|
65822
66280
|
idempotencyKey: input.idempotencyKey,
|
|
65823
|
-
requestDigest:
|
|
66281
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65824
66282
|
returnUrl: input.returnUrl,
|
|
65825
66283
|
attempt: {
|
|
65826
66284
|
id,
|
|
@@ -65958,7 +66416,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65958
66416
|
return beginConnectAttempt(tx, scope, {
|
|
65959
66417
|
...continuation ? { externalContinuation: continuation } : {},
|
|
65960
66418
|
idempotencyKey: input.idempotencyKey,
|
|
65961
|
-
requestDigest:
|
|
66419
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65962
66420
|
returnUrl: input.returnUrl,
|
|
65963
66421
|
attempt: {
|
|
65964
66422
|
id,
|
|
@@ -67015,7 +67473,7 @@ function requireOrganizationDocumentAuthority(authorityKind, organizationAuthori
|
|
|
67015
67473
|
}
|
|
67016
67474
|
|
|
67017
67475
|
// src/routes/knowledge.ts
|
|
67018
|
-
import { retryWhileMissing as
|
|
67476
|
+
import { retryWhileMissing as retryWhileMissing5 } from "@opengeni/storage";
|
|
67019
67477
|
import { allowedFirstPartyMcpToolsForSession as allowedFirstPartyMcpToolsForSession3 } from "@opengeni/config";
|
|
67020
67478
|
import {
|
|
67021
67479
|
AgentLearningContext,
|
|
@@ -67155,7 +67613,7 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67155
67613
|
if (!file) throw new HTTPException42(404, { message: "Original file unavailable" });
|
|
67156
67614
|
if (!deps.objectStorage)
|
|
67157
67615
|
throw new HTTPException42(503, { message: "File storage is unavailable" });
|
|
67158
|
-
if (!await
|
|
67616
|
+
if (!await retryWhileMissing5(
|
|
67159
67617
|
async () => await deps.objectStorage.fileExists(file) ? true : null
|
|
67160
67618
|
))
|
|
67161
67619
|
throw new HTTPException42(410, { message: "Original file bytes are unavailable" });
|
|
@@ -67432,7 +67890,7 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67432
67890
|
}
|
|
67433
67891
|
|
|
67434
67892
|
// src/routes/enrollments.ts
|
|
67435
|
-
import { randomUUID as
|
|
67893
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
67436
67894
|
import {
|
|
67437
67895
|
DeviceEnrollmentApproveRequest,
|
|
67438
67896
|
DeviceEnrollmentApproveResponse,
|
|
@@ -67464,297 +67922,6 @@ import {
|
|
|
67464
67922
|
requireAccessGrantAuthorization as requireAccessGrantAuthorization10,
|
|
67465
67923
|
requirePermission
|
|
67466
67924
|
} from "@opengeni/core";
|
|
67467
|
-
|
|
67468
|
-
// src/sandbox/enrollment.ts
|
|
67469
|
-
import { randomBytes as randomBytes8 } from "crypto";
|
|
67470
|
-
import {
|
|
67471
|
-
resolveEnrollmentSigningSecret,
|
|
67472
|
-
resolveRelayTokenSecret
|
|
67473
|
-
} from "@opengeni/config";
|
|
67474
|
-
import {
|
|
67475
|
-
DeviceEnrollmentState,
|
|
67476
|
-
signEnrollmentBearer,
|
|
67477
|
-
signEnrollToken,
|
|
67478
|
-
signRelayToken,
|
|
67479
|
-
verifyEnrollToken
|
|
67480
|
-
} from "@opengeni/contracts";
|
|
67481
|
-
import {
|
|
67482
|
-
approveDeviceEnrollmentRequest,
|
|
67483
|
-
consumeDeviceEnrollmentRequest,
|
|
67484
|
-
createDeviceEnrollmentRequest,
|
|
67485
|
-
denyDeviceEnrollmentRequest,
|
|
67486
|
-
finalizeEnrollmentByToken,
|
|
67487
|
-
getDeviceEnrollmentRequestByDeviceCode,
|
|
67488
|
-
getEnrollment,
|
|
67489
|
-
getPendingDeviceEnrollmentRequestByUserCode,
|
|
67490
|
-
getPendingDeviceEnrollmentRequestByUserCodeGlobal
|
|
67491
|
-
} from "@opengeni/db";
|
|
67492
|
-
import { relayDialBaseFromSettings } from "@opengeni/core";
|
|
67493
|
-
var DEVICE_CODE_TTL_SECONDS = 600;
|
|
67494
|
-
var DEVICE_POLL_INTERVAL_SECONDS = 5;
|
|
67495
|
-
var ENROLLMENT_BEARER_TTL_SECONDS = 30 * 24 * 3600;
|
|
67496
|
-
var RELAY_TOKEN_TTL_SECONDS = 30 * 24 * 3600;
|
|
67497
|
-
var ENROLL_TOKEN_TTL_SECONDS = 3600;
|
|
67498
|
-
function mintDeviceCode() {
|
|
67499
|
-
return randomBytes8(32).toString("base64url");
|
|
67500
|
-
}
|
|
67501
|
-
var USER_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
67502
|
-
function mintUserCode() {
|
|
67503
|
-
const bytes = randomBytes8(8);
|
|
67504
|
-
let out = "";
|
|
67505
|
-
for (let i = 0; i < 8; i += 1) {
|
|
67506
|
-
out += USER_CODE_ALPHABET[bytes[i] % USER_CODE_ALPHABET.length];
|
|
67507
|
-
}
|
|
67508
|
-
return `${out.slice(0, 4)}-${out.slice(4, 8)}`;
|
|
67509
|
-
}
|
|
67510
|
-
async function startDeviceEnrollment(services, input) {
|
|
67511
|
-
const { db } = services;
|
|
67512
|
-
const expiresAt = new Date(Date.now() + DEVICE_CODE_TTL_SECONDS * 1e3);
|
|
67513
|
-
let request;
|
|
67514
|
-
let lastError;
|
|
67515
|
-
for (let attempt = 0; attempt < 5 && !request; attempt += 1) {
|
|
67516
|
-
const deviceCode = mintDeviceCode();
|
|
67517
|
-
const userCode = mintUserCode();
|
|
67518
|
-
try {
|
|
67519
|
-
request = await createDeviceEnrollmentRequest(db, {
|
|
67520
|
-
accountId: input.accountId,
|
|
67521
|
-
workspaceId: input.workspaceId,
|
|
67522
|
-
deviceCode,
|
|
67523
|
-
userCode,
|
|
67524
|
-
pubkey: input.publicKey,
|
|
67525
|
-
os: input.os,
|
|
67526
|
-
arch: input.arch,
|
|
67527
|
-
machineName: input.machineName ?? null,
|
|
67528
|
-
requestedExposure: "whole-machine",
|
|
67529
|
-
canOfferDisplay: input.canOfferDisplay,
|
|
67530
|
-
requestsScreenControl: input.requestsScreenControl,
|
|
67531
|
-
expiresAt
|
|
67532
|
-
});
|
|
67533
|
-
} catch (error) {
|
|
67534
|
-
lastError = error;
|
|
67535
|
-
}
|
|
67536
|
-
}
|
|
67537
|
-
if (!request) {
|
|
67538
|
-
throw lastError instanceof Error ? lastError : new Error("failed to start device enrollment");
|
|
67539
|
-
}
|
|
67540
|
-
const base = input.verificationOrigin.replace(/\/+$/, "");
|
|
67541
|
-
const verificationUri = `${base}/device`;
|
|
67542
|
-
const verificationUriComplete = `${verificationUri}?user_code=${encodeURIComponent(request.userCode)}`;
|
|
67543
|
-
return {
|
|
67544
|
-
deviceCode: request.deviceCode,
|
|
67545
|
-
userCode: request.userCode,
|
|
67546
|
-
verificationUri,
|
|
67547
|
-
verificationUriComplete,
|
|
67548
|
-
intervalSeconds: DEVICE_POLL_INTERVAL_SECONDS,
|
|
67549
|
-
expiresInSeconds: DEVICE_CODE_TTL_SECONDS
|
|
67550
|
-
};
|
|
67551
|
-
}
|
|
67552
|
-
async function approveDeviceEnrollment(services, input) {
|
|
67553
|
-
const { db } = services;
|
|
67554
|
-
const pending = await getPendingDeviceEnrollmentRequestByUserCode(
|
|
67555
|
-
db,
|
|
67556
|
-
input.workspaceId,
|
|
67557
|
-
input.userCode
|
|
67558
|
-
);
|
|
67559
|
-
if (!pending) {
|
|
67560
|
-
return null;
|
|
67561
|
-
}
|
|
67562
|
-
const sandboxName = (pending.machineName?.trim() || `${pending.os} machine`).slice(0, 256);
|
|
67563
|
-
const result = await approveDeviceEnrollmentRequest(db, {
|
|
67564
|
-
accountId: input.accountId,
|
|
67565
|
-
workspaceId: input.workspaceId,
|
|
67566
|
-
...input.scope ? { scope: input.scope } : {},
|
|
67567
|
-
allowOrganization: input.allowOrganization === true,
|
|
67568
|
-
requestId: pending.id,
|
|
67569
|
-
allowScreenControl: input.allowScreenControl,
|
|
67570
|
-
approvedBySubjectId: input.approvedBySubjectId,
|
|
67571
|
-
approvedBySubjectLabel: input.approvedBySubjectLabel ?? null,
|
|
67572
|
-
sandboxName
|
|
67573
|
-
});
|
|
67574
|
-
if (!result.approved || !result.enrollment || !result.sandbox) {
|
|
67575
|
-
return null;
|
|
67576
|
-
}
|
|
67577
|
-
return {
|
|
67578
|
-
enrollmentId: result.enrollment.id,
|
|
67579
|
-
sandboxId: result.sandbox.id,
|
|
67580
|
-
allowScreenControl: result.enrollment.allowScreenControl
|
|
67581
|
-
};
|
|
67582
|
-
}
|
|
67583
|
-
async function lookupDeviceEnrollment(services, input) {
|
|
67584
|
-
const { db } = services;
|
|
67585
|
-
return await getPendingDeviceEnrollmentRequestByUserCodeGlobal(db, input.userCode);
|
|
67586
|
-
}
|
|
67587
|
-
function toLookupResponse(record6) {
|
|
67588
|
-
return {
|
|
67589
|
-
workspaceId: record6.workspaceId,
|
|
67590
|
-
userCode: record6.userCode,
|
|
67591
|
-
machine: {
|
|
67592
|
-
machineName: record6.machineName,
|
|
67593
|
-
os: record6.os,
|
|
67594
|
-
arch: record6.arch,
|
|
67595
|
-
canOfferDisplay: record6.canOfferDisplay,
|
|
67596
|
-
requestsScreenControl: record6.requestsScreenControl
|
|
67597
|
-
},
|
|
67598
|
-
expiresAt: record6.expiresAt
|
|
67599
|
-
};
|
|
67600
|
-
}
|
|
67601
|
-
async function denyDeviceEnrollment(services, input) {
|
|
67602
|
-
const { db } = services;
|
|
67603
|
-
const pending = await getPendingDeviceEnrollmentRequestByUserCode(
|
|
67604
|
-
db,
|
|
67605
|
-
input.workspaceId,
|
|
67606
|
-
input.userCode
|
|
67607
|
-
);
|
|
67608
|
-
if (!pending) {
|
|
67609
|
-
return { denied: false };
|
|
67610
|
-
}
|
|
67611
|
-
return await denyDeviceEnrollmentRequest(db, {
|
|
67612
|
-
accountId: input.accountId,
|
|
67613
|
-
workspaceId: input.workspaceId,
|
|
67614
|
-
requestId: pending.id
|
|
67615
|
-
});
|
|
67616
|
-
}
|
|
67617
|
-
async function mintEnrollToken(services, input) {
|
|
67618
|
-
const { settings } = services;
|
|
67619
|
-
const secret = resolveEnrollmentSigningSecret(settings);
|
|
67620
|
-
if (!secret) {
|
|
67621
|
-
return null;
|
|
67622
|
-
}
|
|
67623
|
-
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
67624
|
-
const exp = nowSeconds + ENROLL_TOKEN_TTL_SECONDS;
|
|
67625
|
-
const token = await signEnrollToken(secret, {
|
|
67626
|
-
typ: "enroll",
|
|
67627
|
-
workspaceId: input.workspaceId,
|
|
67628
|
-
accountId: input.accountId,
|
|
67629
|
-
allowScreenControl: input.allowScreenControl,
|
|
67630
|
-
iat: nowSeconds,
|
|
67631
|
-
exp
|
|
67632
|
-
});
|
|
67633
|
-
return {
|
|
67634
|
-
token,
|
|
67635
|
-
expiresAt: new Date(exp * 1e3).toISOString(),
|
|
67636
|
-
expiresInSeconds: ENROLL_TOKEN_TTL_SECONDS
|
|
67637
|
-
};
|
|
67638
|
-
}
|
|
67639
|
-
async function exchangeEnrollToken(services, input) {
|
|
67640
|
-
const { db, settings } = services;
|
|
67641
|
-
const secret = resolveEnrollmentSigningSecret(settings);
|
|
67642
|
-
if (!secret) {
|
|
67643
|
-
return { ok: false, reason: "disabled" };
|
|
67644
|
-
}
|
|
67645
|
-
const claims = await verifyEnrollToken(secret, input.token);
|
|
67646
|
-
if (!claims) {
|
|
67647
|
-
return { ok: false, reason: "invalid" };
|
|
67648
|
-
}
|
|
67649
|
-
const sandboxName = (input.machineName?.trim() || `${input.os} machine`).slice(0, 256);
|
|
67650
|
-
const { enrollment } = await finalizeEnrollmentByToken(db, {
|
|
67651
|
-
accountId: claims.accountId,
|
|
67652
|
-
workspaceId: claims.workspaceId,
|
|
67653
|
-
pubkey: input.publicKey,
|
|
67654
|
-
hasDisplay: input.canOfferDisplay,
|
|
67655
|
-
// The token's allowScreenControl is the AUTHORITATIVE consent (NOT the agent's
|
|
67656
|
-
// requestsScreenControl) — it was baked in at mint by the authorizing user.
|
|
67657
|
-
allowScreenControl: claims.allowScreenControl,
|
|
67658
|
-
os: input.os,
|
|
67659
|
-
arch: input.arch,
|
|
67660
|
-
sandboxName
|
|
67661
|
-
});
|
|
67662
|
-
const credentials = await buildEnrollmentCredentials(services, {
|
|
67663
|
-
secret,
|
|
67664
|
-
workspaceId: claims.workspaceId,
|
|
67665
|
-
agentId: enrollment.id,
|
|
67666
|
-
credentialGeneration: enrollment.credentialGeneration,
|
|
67667
|
-
consentedScreenControl: enrollment.allowScreenControl
|
|
67668
|
-
});
|
|
67669
|
-
return { ok: true, credentials };
|
|
67670
|
-
}
|
|
67671
|
-
async function pollDeviceEnrollment(services, input) {
|
|
67672
|
-
const { db, settings } = services;
|
|
67673
|
-
const request = await getDeviceEnrollmentRequestByDeviceCode(db, input.deviceCode);
|
|
67674
|
-
if (!request) {
|
|
67675
|
-
return { state: "expired" };
|
|
67676
|
-
}
|
|
67677
|
-
if (request.status === "denied") {
|
|
67678
|
-
return { state: "denied" };
|
|
67679
|
-
}
|
|
67680
|
-
if (request.status === "pending") {
|
|
67681
|
-
if (new Date(request.expiresAt).getTime() <= Date.now()) {
|
|
67682
|
-
return { state: "expired" };
|
|
67683
|
-
}
|
|
67684
|
-
return { state: "pending" };
|
|
67685
|
-
}
|
|
67686
|
-
if (!request.enrollmentId) {
|
|
67687
|
-
return { state: "expired" };
|
|
67688
|
-
}
|
|
67689
|
-
const secret = resolveEnrollmentSigningSecret(settings);
|
|
67690
|
-
if (!secret) {
|
|
67691
|
-
return { state: "disabled" };
|
|
67692
|
-
}
|
|
67693
|
-
const enrollment = await getEnrollment(db, request.workspaceId, request.enrollmentId);
|
|
67694
|
-
if (!enrollment || enrollment.status !== "active") {
|
|
67695
|
-
return { state: "denied" };
|
|
67696
|
-
}
|
|
67697
|
-
const credentials = await buildEnrollmentCredentials(services, {
|
|
67698
|
-
secret,
|
|
67699
|
-
workspaceId: request.workspaceId,
|
|
67700
|
-
agentId: enrollment.id,
|
|
67701
|
-
credentialGeneration: enrollment.credentialGeneration,
|
|
67702
|
-
consentedScreenControl: enrollment.allowScreenControl
|
|
67703
|
-
});
|
|
67704
|
-
if (request.status === "approved") {
|
|
67705
|
-
await consumeDeviceEnrollmentRequest(db, {
|
|
67706
|
-
accountId: request.accountId,
|
|
67707
|
-
workspaceId: request.workspaceId,
|
|
67708
|
-
requestId: request.id
|
|
67709
|
-
});
|
|
67710
|
-
}
|
|
67711
|
-
return { state: DeviceEnrollmentState.enum.authorized, credentials };
|
|
67712
|
-
}
|
|
67713
|
-
async function buildEnrollmentCredentials(services, input) {
|
|
67714
|
-
const { settings } = services;
|
|
67715
|
-
const subjectPrefix = `agent.${input.workspaceId}.${input.agentId}`;
|
|
67716
|
-
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
67717
|
-
const exp = nowSeconds + ENROLLMENT_BEARER_TTL_SECONDS;
|
|
67718
|
-
const bearer = await signEnrollmentBearer(input.secret, {
|
|
67719
|
-
workspaceId: input.workspaceId,
|
|
67720
|
-
agentId: input.agentId,
|
|
67721
|
-
enrollmentId: input.agentId,
|
|
67722
|
-
credentialGeneration: input.credentialGeneration,
|
|
67723
|
-
subjectPrefix,
|
|
67724
|
-
exp
|
|
67725
|
-
});
|
|
67726
|
-
const natsUrls = settings.selfhostedNatsUrl ? [settings.selfhostedNatsUrl] : [];
|
|
67727
|
-
const relayTokenSecret = resolveRelayTokenSecret(settings);
|
|
67728
|
-
const relayToken = relayTokenSecret ? await signRelayToken(relayTokenSecret, {
|
|
67729
|
-
workspaceId: input.workspaceId,
|
|
67730
|
-
agentId: input.agentId,
|
|
67731
|
-
exp: nowSeconds + RELAY_TOKEN_TTL_SECONDS
|
|
67732
|
-
}) : "";
|
|
67733
|
-
return {
|
|
67734
|
-
agentId: input.agentId,
|
|
67735
|
-
workspaceId: input.workspaceId,
|
|
67736
|
-
bearer,
|
|
67737
|
-
subjectPrefix,
|
|
67738
|
-
natsUrls,
|
|
67739
|
-
// Hand the agent the canonical `/stream` dial base, NOT the raw configured URL.
|
|
67740
|
-
// The agent's relay producer appends only its routing query and assumes the base
|
|
67741
|
-
// already carries the relay's `/stream` route; a path-less base 400s the dial and
|
|
67742
|
-
// makes the terminal/desktop streams unreachable.
|
|
67743
|
-
relayUrl: relayDialBaseFromSettings(settings),
|
|
67744
|
-
relayToken,
|
|
67745
|
-
// M-AUTH closes the placeholder: there is NO per-machine NATS Account creds
|
|
67746
|
-
// file. The agent presents the BEARER as the NATS connect auth-token; the
|
|
67747
|
-
// server's auth-callout responder validates it and mints a workspace-scoped
|
|
67748
|
-
// user JWT. We echo the bearer here so a consumer reading this (vestigial) field
|
|
67749
|
-
// as the connect credential still works — the value IS the bearer.
|
|
67750
|
-
natsAccountCreds: bearer,
|
|
67751
|
-
updatePublicKey: settings.agentUpdatePublicKey ?? "",
|
|
67752
|
-
consentedWholeMachine: true,
|
|
67753
|
-
consentedScreenControl: input.consentedScreenControl
|
|
67754
|
-
};
|
|
67755
|
-
}
|
|
67756
|
-
|
|
67757
|
-
// src/routes/enrollments.ts
|
|
67758
67925
|
function registerEnrollmentRoutes(app, deps) {
|
|
67759
67926
|
const { settings, db } = deps;
|
|
67760
67927
|
function assertSelfhostedEnabled() {
|
|
@@ -68023,7 +68190,7 @@ function registerEnrollmentRoutes(app, deps) {
|
|
|
68023
68190
|
message: "invalid machine removal request"
|
|
68024
68191
|
});
|
|
68025
68192
|
}
|
|
68026
|
-
const idempotencyKey = parsed.data.idempotencyKey?.trim() || c.req.header("idempotency-key")?.trim() ||
|
|
68193
|
+
const idempotencyKey = parsed.data.idempotencyKey?.trim() || c.req.header("idempotency-key")?.trim() || randomUUID6();
|
|
68027
68194
|
try {
|
|
68028
68195
|
const enrollmentId = c.req.param("enrollmentId");
|
|
68029
68196
|
const enrollment = (await listEnrollments2(db, grant, { status: "active" })).find(
|
|
@@ -68154,7 +68321,7 @@ import {
|
|
|
68154
68321
|
readMachineMetricsLatestForWorkspace
|
|
68155
68322
|
} from "@opengeni/db";
|
|
68156
68323
|
import { MachineView, MetricSample } from "@opengeni/contracts";
|
|
68157
|
-
import { managedSessionGroupBackend as managedSessionGroupBackend3 } from "@opengeni/core";
|
|
68324
|
+
import { managedSessionGroupBackend as managedSessionGroupBackend3, sessionGroupMachinePresentation } from "@opengeni/core";
|
|
68158
68325
|
import { selfhostedHeartbeatLiveness } from "@opengeni/runtime/sandbox";
|
|
68159
68326
|
var ACTIVE_UPDATE_STATUSES = /* @__PURE__ */ new Set([
|
|
68160
68327
|
"requested",
|
|
@@ -68291,23 +68458,24 @@ async function listMachines(services, input) {
|
|
|
68291
68458
|
if (session && groupBackend) {
|
|
68292
68459
|
const groupActive = activeSandboxId === null;
|
|
68293
68460
|
const groupLease = await readLease3(db, workspaceId, session.sandboxGroupId);
|
|
68461
|
+
const presentation = sessionGroupMachinePresentation(groupBackend);
|
|
68462
|
+
const localHost = groupBackend === "local";
|
|
68294
68463
|
machines.push(
|
|
68295
68464
|
MachineView.parse({
|
|
68296
68465
|
sandboxId: session.sandboxGroupId,
|
|
68297
68466
|
enrollmentId: null,
|
|
68298
|
-
name:
|
|
68299
|
-
kind:
|
|
68467
|
+
name: presentation.name,
|
|
68468
|
+
kind: presentation.kind,
|
|
68300
68469
|
state: "online",
|
|
68301
68470
|
active: groupActive,
|
|
68302
68471
|
isSessionGroup: true,
|
|
68303
68472
|
workspaceGeneration: groupLease?.workspaceGeneration ?? null,
|
|
68304
68473
|
archiveGeneration: groupLease?.archiveGeneration ?? null,
|
|
68305
68474
|
archiveComplete: groupLease?.archiveComplete ?? false,
|
|
68306
|
-
//
|
|
68307
|
-
|
|
68308
|
-
|
|
68309
|
-
|
|
68310
|
-
hasDisplay: false,
|
|
68475
|
+
// A local sandbox is this machine. Other managed providers run a Linux box.
|
|
68476
|
+
os: localHost ? process.platform : "linux",
|
|
68477
|
+
arch: localHost ? process.arch : "x86_64",
|
|
68478
|
+
hasDisplay: localHost,
|
|
68311
68479
|
desktopUnavailableReason: null,
|
|
68312
68480
|
allowScreenControl: false,
|
|
68313
68481
|
sharedSessionCount: 1,
|
|
@@ -70222,7 +70390,7 @@ function browserIdentityRouteError(error) {
|
|
|
70222
70390
|
}
|
|
70223
70391
|
|
|
70224
70392
|
// src/routes/browser-sessions.ts
|
|
70225
|
-
import { randomUUID as
|
|
70393
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
70226
70394
|
import {
|
|
70227
70395
|
environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes5,
|
|
70228
70396
|
resolveFirstPartyDelegationSecret as resolveFirstPartyDelegationSecret3,
|
|
@@ -70374,7 +70542,7 @@ import {
|
|
|
70374
70542
|
provisionBrowserControlClient,
|
|
70375
70543
|
renewSandboxProviderExpiration as renewSandboxProviderExpiration2
|
|
70376
70544
|
} from "@opengeni/runtime/sandbox";
|
|
70377
|
-
import { retryWhileMissing as
|
|
70545
|
+
import { retryWhileMissing as retryWhileMissing6 } from "@opengeni/storage";
|
|
70378
70546
|
import { HTTPException as HTTPException51 } from "hono/http-exception";
|
|
70379
70547
|
|
|
70380
70548
|
// src/browser-controller-authority.ts
|
|
@@ -70657,7 +70825,7 @@ async function withInteractionHolderHeartbeat(deps, input, run) {
|
|
|
70657
70825
|
}
|
|
70658
70826
|
|
|
70659
70827
|
// src/browser-state-authority.ts
|
|
70660
|
-
import { createCipheriv, createDecipheriv, createHash as
|
|
70828
|
+
import { createCipheriv, createDecipheriv, createHash as createHash19, createHmac as createHmac7, randomBytes as randomBytes9 } from "crypto";
|
|
70661
70829
|
import { BROWSER_PROFILE_ARTIFACT_FORMAT } from "@opengeni/contracts";
|
|
70662
70830
|
var ROOT_KEY_BYTES = 32;
|
|
70663
70831
|
var DATA_KEY_BYTES = 32;
|
|
@@ -70721,7 +70889,7 @@ function browserStateObjectKey(workspaceIdInput, operationIdInput) {
|
|
|
70721
70889
|
return `workspaces/${workspaceId}/browser-state/revisions/${operationId}/chromium-profile.ogbs`;
|
|
70722
70890
|
}
|
|
70723
70891
|
function browserStateManifestDigest(manifest) {
|
|
70724
|
-
return
|
|
70892
|
+
return createHash19("sha256").update(canonicalJson2(manifest), "utf8").digest("hex");
|
|
70725
70893
|
}
|
|
70726
70894
|
function operationScope(input) {
|
|
70727
70895
|
const base = baseArtifactScope(input);
|
|
@@ -72013,7 +72181,7 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
72013
72181
|
message: `browser download exceeds single PUT limit of ${objectStorage.maxSinglePutSizeBytes} bytes`
|
|
72014
72182
|
});
|
|
72015
72183
|
}
|
|
72016
|
-
const fileId =
|
|
72184
|
+
const fileId = randomUUID7();
|
|
72017
72185
|
const safeFilename = sanitizeFilename(source.download.filename);
|
|
72018
72186
|
save = await prepareBrowserDownloadSave(deps.db, {
|
|
72019
72187
|
...identity2,
|
|
@@ -72916,7 +73084,7 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
72916
73084
|
if (!targets.some((target) => target.id === request.targetId)) {
|
|
72917
73085
|
throw new HTTPException51(404, { message: "browser target does not exist" });
|
|
72918
73086
|
}
|
|
72919
|
-
const grantId =
|
|
73087
|
+
const grantId = randomUUID7();
|
|
72920
73088
|
const expiresAt = new Date(Date.now() + request.expiresInSeconds * 1e3).toISOString();
|
|
72921
73089
|
const rootSecret = browserAuthorityRoot(deps);
|
|
72922
73090
|
const relaySecret = placement.session.openBrowserFrames ? resolveStreamTokenSecret2(deps.settings) : null;
|
|
@@ -74664,7 +74832,7 @@ async function ensureDispatchedGeneration(deps, grant, workspaceId, browserSessi
|
|
|
74664
74832
|
operationId
|
|
74665
74833
|
});
|
|
74666
74834
|
if (record6.operation?.state === "prepared") {
|
|
74667
|
-
const controllerGeneration =
|
|
74835
|
+
const controllerGeneration = randomUUID7();
|
|
74668
74836
|
try {
|
|
74669
74837
|
await dispatchBrowserSessionOperation(deps.db, {
|
|
74670
74838
|
accountId: grant.accountId,
|
|
@@ -75273,7 +75441,7 @@ async function finalizeBrowserDownloadFile(deps, grant, workspaceId, uploadId) {
|
|
|
75273
75441
|
throw new InteractionResourceStateError("Browser download file upload authority expired");
|
|
75274
75442
|
}
|
|
75275
75443
|
const pendingFile = upload.file;
|
|
75276
|
-
const head = await
|
|
75444
|
+
const head = await retryWhileMissing6(async () => {
|
|
75277
75445
|
if (!await objectStorage.fileExists(pendingFile)) return null;
|
|
75278
75446
|
return await objectStorage.headFile(pendingFile);
|
|
75279
75447
|
});
|
|
@@ -75364,7 +75532,7 @@ function isAbort(error) {
|
|
|
75364
75532
|
}
|
|
75365
75533
|
|
|
75366
75534
|
// src/routes/computer-sessions.ts
|
|
75367
|
-
import { randomUUID as
|
|
75535
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
75368
75536
|
import { resolveFirstPartyDelegationSecret as resolveFirstPartyDelegationSecret4, resolveStreamTokenSecret as resolveStreamTokenSecret3 } from "@opengeni/config";
|
|
75369
75537
|
import {
|
|
75370
75538
|
BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX as BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX2,
|
|
@@ -75888,7 +76056,7 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
75888
76056
|
retryable: false
|
|
75889
76057
|
});
|
|
75890
76058
|
}
|
|
75891
|
-
const grantId =
|
|
76059
|
+
const grantId = randomUUID8();
|
|
75892
76060
|
const expiresAt = new Date(Date.now() + request.expiresInSeconds * 1e3).toISOString();
|
|
75893
76061
|
const token = deriveComputerViewGrantToken({
|
|
75894
76062
|
rootSecret: controllerAuthorityRoot(deps),
|
|
@@ -76599,7 +76767,7 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
76599
76767
|
operationId
|
|
76600
76768
|
});
|
|
76601
76769
|
if (record6.operation?.state === "prepared") {
|
|
76602
|
-
const controllerGeneration =
|
|
76770
|
+
const controllerGeneration = randomUUID8();
|
|
76603
76771
|
try {
|
|
76604
76772
|
await dispatchComputerSessionOperation(deps.db, {
|
|
76605
76773
|
accountId: grant.accountId,
|
|
@@ -78712,7 +78880,7 @@ import {
|
|
|
78712
78880
|
personalGitHubGitBrokerRouteId
|
|
78713
78881
|
} from "@opengeni/github";
|
|
78714
78882
|
import { readResponseTextBounded as readResponseTextBounded2 } from "@opengeni/network";
|
|
78715
|
-
import { randomUUID as
|
|
78883
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
78716
78884
|
import JSONBig2 from "json-bigint";
|
|
78717
78885
|
var PERSONAL_GITHUB_SERVER_ID = "github:personal";
|
|
78718
78886
|
var GITHUB_API_VERSION3 = "2022-11-28";
|
|
@@ -78930,7 +79098,7 @@ async function authorizeBrokerProviderRequest(deps, authority, destinationUrl, o
|
|
|
78930
79098
|
turnId: claims.turnId,
|
|
78931
79099
|
attemptId: claims.attemptId,
|
|
78932
79100
|
executionGeneration: claims.executionGeneration,
|
|
78933
|
-
physicalRequestId:
|
|
79101
|
+
physicalRequestId: randomUUID9(),
|
|
78934
79102
|
usePhase: "credential_resolution"
|
|
78935
79103
|
}
|
|
78936
79104
|
});
|
|
@@ -78945,7 +79113,7 @@ async function authorizeBrokerProviderRequest(deps, authority, destinationUrl, o
|
|
|
78945
79113
|
turnId: claims.turnId,
|
|
78946
79114
|
attemptId: claims.attemptId,
|
|
78947
79115
|
executionGeneration: claims.executionGeneration,
|
|
78948
|
-
physicalRequestId:
|
|
79116
|
+
physicalRequestId: randomUUID9(),
|
|
78949
79117
|
usePhase: "provider_request",
|
|
78950
79118
|
serverId: PERSONAL_GITHUB_SERVER_ID,
|
|
78951
79119
|
connectionId: claims.connectionId,
|
|
@@ -83105,7 +83273,7 @@ import {
|
|
|
83105
83273
|
integrationSourceForOrganizationPolicy as integrationSourceForOrganizationPolicy2
|
|
83106
83274
|
} from "@opengeni/core";
|
|
83107
83275
|
import { withOrganizationIntegrationPolicyFence as withOrganizationIntegrationPolicyFence8 } from "@opengeni/db/organization-integration-policy";
|
|
83108
|
-
import { createHash as
|
|
83276
|
+
import { createHash as createHash20 } from "crypto";
|
|
83109
83277
|
import {
|
|
83110
83278
|
createPinnedIntegrationTransport as createPinnedIntegrationTransport3,
|
|
83111
83279
|
fetchIntegrationSourceDocument as fetchIntegrationSourceDocument2
|
|
@@ -83967,7 +84135,7 @@ function pluginFailureCode(error) {
|
|
|
83967
84135
|
return "component_install_failed";
|
|
83968
84136
|
}
|
|
83969
84137
|
function sha2562(value) {
|
|
83970
|
-
return
|
|
84138
|
+
return createHash20("sha256").update(value).digest("hex");
|
|
83971
84139
|
}
|
|
83972
84140
|
|
|
83973
84141
|
// src/routes/skills.ts
|
|
@@ -84002,14 +84170,14 @@ import {
|
|
|
84002
84170
|
SkillSourceRemovalAuthorityError as SkillSourceRemovalAuthorityError2
|
|
84003
84171
|
} from "@opengeni/db";
|
|
84004
84172
|
import { loadSkillLibrarySkill, skillLibraryRepositoryUrl } from "@opengeni/runtime/skill-library";
|
|
84005
|
-
import { createHash as
|
|
84173
|
+
import { createHash as createHash21 } from "crypto";
|
|
84006
84174
|
import { HTTPException as HTTPException67 } from "hono/http-exception";
|
|
84007
84175
|
|
|
84008
84176
|
// src/routes/skill-content.ts
|
|
84009
84177
|
import { z as z24 } from "zod";
|
|
84010
84178
|
import { HTTPException as HTTPException66 } from "hono/http-exception";
|
|
84011
|
-
import { SkillFile } from "@opengeni/contracts";
|
|
84012
|
-
import { readSkillRemovalScope } from "@opengeni/db";
|
|
84179
|
+
import { SkillFile, SKILL_MAX_FILES } from "@opengeni/contracts";
|
|
84180
|
+
import { getSessionForSubject, readSkillRemovalScope } from "@opengeni/db";
|
|
84013
84181
|
import {
|
|
84014
84182
|
approveSkill,
|
|
84015
84183
|
rejectSkill,
|
|
@@ -84375,8 +84543,8 @@ var saveRequest = z24.object({
|
|
|
84375
84543
|
expectedScopeVersion: z24.number().int().nonnegative(),
|
|
84376
84544
|
scope: scopeSchema.default("workspace"),
|
|
84377
84545
|
stableKey: z24.string().min(1).max(96),
|
|
84378
|
-
files: z24.array(SkillFile).max(
|
|
84379
|
-
deletions: z24.array(z24.string().min(1).max(512)).max(
|
|
84546
|
+
files: z24.array(SkillFile).max(SKILL_MAX_FILES),
|
|
84547
|
+
deletions: z24.array(z24.string().min(1).max(512)).max(SKILL_MAX_FILES).default([]),
|
|
84380
84548
|
reason: z24.string().min(1).max(2e3)
|
|
84381
84549
|
}).strict();
|
|
84382
84550
|
var revisionRequest = z24.object({
|
|
@@ -84405,9 +84573,20 @@ function registerSkillContentRoutes(app, deps) {
|
|
|
84405
84573
|
const grant = await requireAccessGrant27(c, deps, workspaceId, "workspace:read");
|
|
84406
84574
|
const query = z24.object({
|
|
84407
84575
|
limit: z24.coerce.number().int().min(1).max(250).default(100),
|
|
84408
|
-
cursor: z24.string().max(2048).optional()
|
|
84576
|
+
cursor: z24.string().max(2048).optional(),
|
|
84577
|
+
sessionId: z24.uuid().optional()
|
|
84409
84578
|
}).safeParse(c.req.query());
|
|
84410
84579
|
if (!query.success) throw new HTTPException66(422, { message: "Invalid Skill list query" });
|
|
84580
|
+
if (query.data.sessionId) {
|
|
84581
|
+
await requireAccessGrant27(c, deps, workspaceId, "sessions:read");
|
|
84582
|
+
const session = await getSessionForSubject(
|
|
84583
|
+
deps.db,
|
|
84584
|
+
workspaceId,
|
|
84585
|
+
query.data.sessionId,
|
|
84586
|
+
grant.subjectId
|
|
84587
|
+
);
|
|
84588
|
+
if (!session) throw new HTTPException66(404, { message: "Session not found" });
|
|
84589
|
+
}
|
|
84411
84590
|
let after;
|
|
84412
84591
|
if (query.data.cursor !== void 0) {
|
|
84413
84592
|
try {
|
|
@@ -84419,7 +84598,12 @@ function registerSkillContentRoutes(app, deps) {
|
|
|
84419
84598
|
const rows2 = await listSkills(
|
|
84420
84599
|
deps.db,
|
|
84421
84600
|
{ accountId: grant.accountId, workspaceId, subjectId: grant.subjectId },
|
|
84422
|
-
{
|
|
84601
|
+
{
|
|
84602
|
+
limit: query.data.limit + 1,
|
|
84603
|
+
metadataOnly: true,
|
|
84604
|
+
...after ? { after } : {},
|
|
84605
|
+
...query.data.sessionId ? { sessionId: query.data.sessionId } : {}
|
|
84606
|
+
}
|
|
84423
84607
|
);
|
|
84424
84608
|
const page = rows2.slice(0, query.data.limit);
|
|
84425
84609
|
const last = page.at(-1);
|
|
@@ -84626,7 +84810,7 @@ function registerSkillRoutes(app, deps, overrides = {}) {
|
|
|
84626
84810
|
path: file.path,
|
|
84627
84811
|
content: file.content,
|
|
84628
84812
|
byteSize: bytes.byteLength,
|
|
84629
|
-
contentSha256:
|
|
84813
|
+
contentSha256: createHash21("sha256").update(bytes).digest("hex")
|
|
84630
84814
|
};
|
|
84631
84815
|
});
|
|
84632
84816
|
try {
|
|
@@ -85587,7 +85771,7 @@ import {
|
|
|
85587
85771
|
readActiveSandbox as readActiveSandbox3,
|
|
85588
85772
|
deleteSessionTreeIfQuiescent,
|
|
85589
85773
|
getSessionEvent,
|
|
85590
|
-
getSessionForSubject,
|
|
85774
|
+
getSessionForSubject as getSessionForSubject2,
|
|
85591
85775
|
getSessionGoal as getSessionGoal2,
|
|
85592
85776
|
getLatestSessionModelContext,
|
|
85593
85777
|
getSessionHumanInputRequest,
|
|
@@ -87289,7 +87473,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
87289
87473
|
if (!z27.string().uuid().safeParse(sessionId).success) {
|
|
87290
87474
|
throw new HTTPException72(404, { message: "session not found" });
|
|
87291
87475
|
}
|
|
87292
|
-
const session = await
|
|
87476
|
+
const session = await getSessionForSubject2(
|
|
87293
87477
|
db,
|
|
87294
87478
|
workspaceId,
|
|
87295
87479
|
sessionId,
|
|
@@ -87320,7 +87504,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
87320
87504
|
if (!z27.string().uuid().safeParse(sessionId).success) {
|
|
87321
87505
|
throw new HTTPException72(404, { message: "session not found" });
|
|
87322
87506
|
}
|
|
87323
|
-
const session = await
|
|
87507
|
+
const session = await getSessionForSubject2(
|
|
87324
87508
|
db,
|
|
87325
87509
|
workspaceId,
|
|
87326
87510
|
sessionId,
|
|
@@ -88346,7 +88530,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
88346
88530
|
}
|
|
88347
88531
|
throw error;
|
|
88348
88532
|
}
|
|
88349
|
-
const session = await
|
|
88533
|
+
const session = await getSessionForSubject2(
|
|
88350
88534
|
db,
|
|
88351
88535
|
workspaceId,
|
|
88352
88536
|
sessionId,
|
|
@@ -88421,7 +88605,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
88421
88605
|
if (result.status === "updated") {
|
|
88422
88606
|
await publishDurableSessionEvents3(bus, workspaceId, sessionId, [result.event]);
|
|
88423
88607
|
}
|
|
88424
|
-
const session = await
|
|
88608
|
+
const session = await getSessionForSubject2(
|
|
88425
88609
|
db,
|
|
88426
88610
|
workspaceId,
|
|
88427
88611
|
sessionId,
|
|
@@ -88440,7 +88624,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
88440
88624
|
await assertSessionExists(db, workspaceId, sessionId);
|
|
88441
88625
|
const payload = UpdateSessionRequest.parse(await c.req.json());
|
|
88442
88626
|
const titleUpdate = await updateSessionTitle2(deps, grant, sessionId, payload.title, "user");
|
|
88443
|
-
const session = await
|
|
88627
|
+
const session = await getSessionForSubject2(
|
|
88444
88628
|
db,
|
|
88445
88629
|
workspaceId,
|
|
88446
88630
|
sessionId,
|
|
@@ -91508,7 +91692,7 @@ import { SessionControlConflictError as SessionControlConflictError2, WorkspaceP
|
|
|
91508
91692
|
import { updateWorkspaceSettingsWithToolDefaults } from "@opengeni/db/workspace-tool-defaults";
|
|
91509
91693
|
import { WorkspacePauseTimerRequest } from "@opengeni/contracts";
|
|
91510
91694
|
import { getWorkspaceConnectionModelRestrictions } from "@opengeni/db";
|
|
91511
|
-
import { createHash as
|
|
91695
|
+
import { createHash as createHash22 } from "crypto";
|
|
91512
91696
|
import {
|
|
91513
91697
|
AddWorkspaceMemberRequest,
|
|
91514
91698
|
CreateWorkspaceRequest,
|
|
@@ -91775,7 +91959,7 @@ function projectWorkspaceOpenRouterCustomModel(model) {
|
|
|
91775
91959
|
});
|
|
91776
91960
|
}
|
|
91777
91961
|
function workspaceCustomModelRequestHash(value) {
|
|
91778
|
-
return
|
|
91962
|
+
return createHash22("sha256").update(stableJson7(value), "utf8").digest("hex");
|
|
91779
91963
|
}
|
|
91780
91964
|
function workspaceMembersResponse(members) {
|
|
91781
91965
|
return ListWorkspaceMembersResponse.parse({
|
|
@@ -92712,7 +92896,7 @@ function requireAccountPermission2(context, accountId, permission) {
|
|
|
92712
92896
|
}
|
|
92713
92897
|
|
|
92714
92898
|
// src/routes/workspace-instruction-policies.ts
|
|
92715
|
-
import { randomUUID as
|
|
92899
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
92716
92900
|
import {
|
|
92717
92901
|
ActivateWorkspaceInstructionPolicyRequest,
|
|
92718
92902
|
CreateWorkspaceInstructionPolicyDraftRequest,
|
|
@@ -92878,7 +93062,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
92878
93062
|
return context.json(
|
|
92879
93063
|
WorkspaceInstructionPolicyRevision.parse(
|
|
92880
93064
|
await createWorkspaceInstructionPolicyDraft(deps.db, {
|
|
92881
|
-
operationId: request.operationId ??
|
|
93065
|
+
operationId: request.operationId ?? randomUUID10(),
|
|
92882
93066
|
accountId: grant.accountId,
|
|
92883
93067
|
workspaceId,
|
|
92884
93068
|
createdBySubjectId: grant.subjectId,
|
|
@@ -92906,7 +93090,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
92906
93090
|
return context.json(
|
|
92907
93091
|
WorkspaceInstructionPolicyRevision.parse(
|
|
92908
93092
|
await importLegacyWorkspaceInstructionPolicyDraft(deps.db, {
|
|
92909
|
-
operationId: request.operationId ??
|
|
93093
|
+
operationId: request.operationId ?? randomUUID10(),
|
|
92910
93094
|
accountId: grant.accountId,
|
|
92911
93095
|
workspaceId,
|
|
92912
93096
|
createdBySubjectId: grant.subjectId,
|
|
@@ -92948,7 +93132,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
92948
93132
|
return context.json(
|
|
92949
93133
|
WorkspaceInstructionPolicyOnboardingProposal.parse(
|
|
92950
93134
|
await createWorkspaceInstructionPolicyOnboardingProposal(deps.db, {
|
|
92951
|
-
operationId: request.operationId ??
|
|
93135
|
+
operationId: request.operationId ?? randomUUID10(),
|
|
92952
93136
|
accountId: grant.accountId,
|
|
92953
93137
|
workspaceId,
|
|
92954
93138
|
createdBySubjectId: grant.subjectId,
|
|
@@ -92998,7 +93182,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
92998
93182
|
return context.json(
|
|
92999
93183
|
WorkspaceInstructionPolicyActivationResponse.parse(
|
|
93000
93184
|
await rollbackWorkspaceInstructionPolicyRevision(deps.db, {
|
|
93001
|
-
operationId: request.operationId ??
|
|
93185
|
+
operationId: request.operationId ?? randomUUID10(),
|
|
93002
93186
|
accountId: grant.accountId,
|
|
93003
93187
|
workspaceId,
|
|
93004
93188
|
targetRevisionId: request.targetRevisionId,
|
|
@@ -93037,7 +93221,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
93037
93221
|
return context.json(
|
|
93038
93222
|
WorkspaceInstructionPolicyActivationResponse.parse(
|
|
93039
93223
|
await activateWorkspaceInstructionPolicyRevision(deps.db, {
|
|
93040
|
-
operationId: request.operationId ??
|
|
93224
|
+
operationId: request.operationId ?? randomUUID10(),
|
|
93041
93225
|
accountId: grant.accountId,
|
|
93042
93226
|
workspaceId,
|
|
93043
93227
|
revisionId: revisionId2,
|
|
@@ -93055,7 +93239,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
93055
93239
|
}
|
|
93056
93240
|
|
|
93057
93241
|
// src/routes/workspace-learning.ts
|
|
93058
|
-
import { randomUUID as
|
|
93242
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
93059
93243
|
import {
|
|
93060
93244
|
UndoGovernedLearningActivationHttpRequest,
|
|
93061
93245
|
WorkspaceLearningHistoryResponse,
|
|
@@ -93178,7 +93362,7 @@ function registerWorkspaceLearningRoutes(app, deps) {
|
|
|
93178
93362
|
const undo = await undoGovernedLearningActivation(deps.db, {
|
|
93179
93363
|
caller: { workspaceId, subjectId: grant.subjectId },
|
|
93180
93364
|
request: {
|
|
93181
|
-
operationId: request.operationId ??
|
|
93365
|
+
operationId: request.operationId ?? randomUUID11(),
|
|
93182
93366
|
activationReceiptId: activationReceiptId.data
|
|
93183
93367
|
}
|
|
93184
93368
|
});
|
|
@@ -93193,7 +93377,7 @@ function registerWorkspaceLearningRoutes(app, deps) {
|
|
|
93193
93377
|
}
|
|
93194
93378
|
|
|
93195
93379
|
// src/routes/company-profile.ts
|
|
93196
|
-
import { randomUUID as
|
|
93380
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
93197
93381
|
import {
|
|
93198
93382
|
ActivateCompanyProfileRevisionRequest,
|
|
93199
93383
|
CompanyProfileAgentPolicy,
|
|
@@ -93370,7 +93554,7 @@ function registerCompanyProfileRoutes(app, deps) {
|
|
|
93370
93554
|
return context.json(
|
|
93371
93555
|
CompanyProfileMutationResponse.parse(
|
|
93372
93556
|
await updateCompanyProfile(deps.db, {
|
|
93373
|
-
operationId: request.operationId ??
|
|
93557
|
+
operationId: request.operationId ?? randomUUID12(),
|
|
93374
93558
|
accountId: access.grant.accountId,
|
|
93375
93559
|
workspaceId,
|
|
93376
93560
|
profile: request.profile,
|
|
@@ -93422,7 +93606,7 @@ function registerCompanyProfileRoutes(app, deps) {
|
|
|
93422
93606
|
return context.json(
|
|
93423
93607
|
CompanyProfileMutationResponse.parse(
|
|
93424
93608
|
await rollbackCompanyProfileRevision(deps.db, {
|
|
93425
|
-
operationId: request.operationId ??
|
|
93609
|
+
operationId: request.operationId ?? randomUUID12(),
|
|
93426
93610
|
accountId: access.grant.accountId,
|
|
93427
93611
|
workspaceId,
|
|
93428
93612
|
targetRevisionId: request.targetRevisionId,
|
|
@@ -93469,7 +93653,7 @@ function registerCompanyProfileRoutes(app, deps) {
|
|
|
93469
93653
|
return context.json(
|
|
93470
93654
|
CompanyProfileMutationResponse.parse(
|
|
93471
93655
|
await activateCompanyProfileRevision(deps.db, {
|
|
93472
|
-
operationId: request.operationId ??
|
|
93656
|
+
operationId: request.operationId ?? randomUUID12(),
|
|
93473
93657
|
accountId: access.grant.accountId,
|
|
93474
93658
|
workspaceId,
|
|
93475
93659
|
revisionId: revisionId(context),
|
|
@@ -93488,7 +93672,7 @@ function registerCompanyProfileRoutes(app, deps) {
|
|
|
93488
93672
|
}
|
|
93489
93673
|
|
|
93490
93674
|
// src/routes/company-brain.ts
|
|
93491
|
-
import { createHash as
|
|
93675
|
+
import { createHash as createHash24 } from "crypto";
|
|
93492
93676
|
import {
|
|
93493
93677
|
COMPANY_BRAIN_INSPECTOR_CURSOR_MAX_CHARS,
|
|
93494
93678
|
COMPANY_BRAIN_INSPECTOR_DEFAULT_LIMIT,
|
|
@@ -93759,14 +93943,14 @@ function serializeCompanyBrainOkf(value) {
|
|
|
93759
93943
|
}
|
|
93760
93944
|
|
|
93761
93945
|
// src/workspace-state-projection.ts
|
|
93762
|
-
import { createHash as
|
|
93946
|
+
import { createHash as createHash23 } from "crypto";
|
|
93763
93947
|
import {
|
|
93764
93948
|
WORKSPACE_STATE_MAX_ACTIVE_POLICY_HEADS,
|
|
93765
93949
|
WORKSPACE_STATE_KNOWLEDGE_SAMPLE_LIMIT,
|
|
93766
93950
|
WorkspaceStateResponse
|
|
93767
93951
|
} from "@opengeni/contracts";
|
|
93768
93952
|
function hashIdentities(values) {
|
|
93769
|
-
return
|
|
93953
|
+
return createHash23("sha256").update(values.join("\n"), "utf8").digest("hex");
|
|
93770
93954
|
}
|
|
93771
93955
|
function policyTargetKey(value) {
|
|
93772
93956
|
return `${value.kind}:${value.scope}:${value.roleKey ?? ""}`;
|
|
@@ -93996,7 +94180,7 @@ var inspectorQuery = z32.object({
|
|
|
93996
94180
|
message: "attemptId cannot be combined with cursor"
|
|
93997
94181
|
});
|
|
93998
94182
|
function receiptCursorScope(workspaceId, subjectId) {
|
|
93999
|
-
return
|
|
94183
|
+
return createHash24("sha256").update("opengeni:company-brain-context-receipts:v1\0").update(workspaceId).update("\0").update(subjectId).digest("hex");
|
|
94000
94184
|
}
|
|
94001
94185
|
function encodeReceiptCursor(workspaceId, subjectId, cursor) {
|
|
94002
94186
|
return Buffer.from(
|
|
@@ -94212,7 +94396,7 @@ function registerCompanyBrainRoutes(app, deps) {
|
|
|
94212
94396
|
}
|
|
94213
94397
|
|
|
94214
94398
|
// src/routes/slack-task-policy.ts
|
|
94215
|
-
import { randomUUID as
|
|
94399
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
94216
94400
|
import {
|
|
94217
94401
|
SlackTaskPolicyListResponse,
|
|
94218
94402
|
SlackTaskPolicyMutationResponse,
|
|
@@ -94295,7 +94479,7 @@ function registerSlackTaskPolicyRoutes(app, deps) {
|
|
|
94295
94479
|
return context.json(
|
|
94296
94480
|
SlackTaskPolicyMutationResponse.parse(
|
|
94297
94481
|
await updateSlackTaskPolicy(deps.db, {
|
|
94298
|
-
operationId: parsed.data.operationId ??
|
|
94482
|
+
operationId: parsed.data.operationId ?? randomUUID13(),
|
|
94299
94483
|
accountId: access.grant.accountId,
|
|
94300
94484
|
workspaceId,
|
|
94301
94485
|
policy: parsed.data.policy,
|
|
@@ -94334,7 +94518,7 @@ import {
|
|
|
94334
94518
|
import { HTTPException as HTTPException81 } from "hono/http-exception";
|
|
94335
94519
|
|
|
94336
94520
|
// src/workspace-state-export.ts
|
|
94337
|
-
import { createHash as
|
|
94521
|
+
import { createHash as createHash25 } from "crypto";
|
|
94338
94522
|
import {
|
|
94339
94523
|
WORKSPACE_STATE_EXPORT_SCHEMA_VERSION,
|
|
94340
94524
|
WorkspaceStateExportResponse
|
|
@@ -94365,7 +94549,7 @@ function createWorkspaceStateExport(state) {
|
|
|
94365
94549
|
kind: "opengeni.workspace_state.sanitized_export",
|
|
94366
94550
|
schemaVersion: WORKSPACE_STATE_EXPORT_SCHEMA_VERSION,
|
|
94367
94551
|
generatedAt: state.generatedAt,
|
|
94368
|
-
stateSha256:
|
|
94552
|
+
stateSha256: createHash25("sha256").update(canonicalState, "utf8").digest("hex"),
|
|
94369
94553
|
omissions: WORKSPACE_STATE_EXPORT_OMISSIONS,
|
|
94370
94554
|
state
|
|
94371
94555
|
});
|
|
@@ -94473,7 +94657,7 @@ function registerWorkspaceStateRoutes(app, deps) {
|
|
|
94473
94657
|
}
|
|
94474
94658
|
|
|
94475
94659
|
// src/routes/workspace-artifacts.ts
|
|
94476
|
-
import { createHash as
|
|
94660
|
+
import { createHash as createHash26 } from "crypto";
|
|
94477
94661
|
import {
|
|
94478
94662
|
CreateWorkspaceArtifactRequest,
|
|
94479
94663
|
PublishWorkspaceArtifactVersionRequest,
|
|
@@ -94565,7 +94749,7 @@ function prepareContent(deps, grant, input) {
|
|
|
94565
94749
|
}
|
|
94566
94750
|
function provenance(subjectId, idempotencyKey) {
|
|
94567
94751
|
return {
|
|
94568
|
-
operationKey: `subject:${
|
|
94752
|
+
operationKey: `subject:${createHash26("sha256").update(`${subjectId}:${idempotencyKey}`).digest("hex")}`,
|
|
94569
94753
|
actorSubjectId: subjectId,
|
|
94570
94754
|
sourceSessionId: null,
|
|
94571
94755
|
sourceTurnId: null,
|
|
@@ -94924,7 +95108,7 @@ import {
|
|
|
94924
95108
|
import { HTTPException as HTTPException84 } from "hono/http-exception";
|
|
94925
95109
|
|
|
94926
95110
|
// src/artifact-catalog-cursor.ts
|
|
94927
|
-
import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, createHash as
|
|
95111
|
+
import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, createHash as createHash27, randomBytes as randomBytes11 } from "crypto";
|
|
94928
95112
|
import { ArtifactCatalogKind } from "@opengeni/contracts";
|
|
94929
95113
|
import { HTTPException as HTTPException83 } from "hono/http-exception";
|
|
94930
95114
|
import { z as z34 } from "zod";
|
|
@@ -94939,8 +95123,8 @@ var Cursor = z34.object({
|
|
|
94939
95123
|
}).strict()
|
|
94940
95124
|
}).strict();
|
|
94941
95125
|
function artifactCatalogCursorCodec(secret, binding) {
|
|
94942
|
-
const key =
|
|
94943
|
-
const aad =
|
|
95126
|
+
const key = createHash27("sha256").update("opengeni:artifact-catalog:v1\0").update(secret).digest();
|
|
95127
|
+
const aad = createHash27("sha256").update(binding).digest();
|
|
94944
95128
|
return {
|
|
94945
95129
|
encode(value) {
|
|
94946
95130
|
const iv = randomBytes11(12);
|
|
@@ -95257,7 +95441,7 @@ import { requireAccessGrant as requireAccessGrant43, TranscriptionServiceError a
|
|
|
95257
95441
|
import { getWorkspace as getWorkspace6 } from "@opengeni/db";
|
|
95258
95442
|
|
|
95259
95443
|
// src/routes/transcription-recordings.ts
|
|
95260
|
-
import { createHash as
|
|
95444
|
+
import { createHash as createHash28 } from "crypto";
|
|
95261
95445
|
import {
|
|
95262
95446
|
CreateTranscriptionRecordingRequest,
|
|
95263
95447
|
FinalizeTranscriptionRecordingRequest,
|
|
@@ -95273,7 +95457,7 @@ import {
|
|
|
95273
95457
|
TRANSCRIPTION_PROVIDER_REQUEST_TIMEOUT_MILLISECONDS,
|
|
95274
95458
|
TranscriptionServiceError
|
|
95275
95459
|
} from "@opengeni/core";
|
|
95276
|
-
import { retryWhileMissing as
|
|
95460
|
+
import { retryWhileMissing as retryWhileMissing7 } from "@opengeni/storage";
|
|
95277
95461
|
import {
|
|
95278
95462
|
claimNextTranscriptionRecordingSegment,
|
|
95279
95463
|
claimTranscriptionRecordingAssembly,
|
|
@@ -95859,7 +96043,7 @@ function registerResumableTranscriptionRoutes(app, deps) {
|
|
|
95859
96043
|
attemptedProvider = claim.segment.providerId;
|
|
95860
96044
|
fallbackAllowed = claim.fallbackAllowed === true;
|
|
95861
96045
|
const segmentKey = claim.segment.objectKey;
|
|
95862
|
-
const stored = deps.objectStorage ? await
|
|
96046
|
+
const stored = deps.objectStorage ? await retryWhileMissing7(async () => deps.objectStorage.getObjectBytes(segmentKey)) : null;
|
|
95863
96047
|
if (!stored) {
|
|
95864
96048
|
throw new RecordingProcessingError("Provider segment is missing", "invalid_audio", false);
|
|
95865
96049
|
}
|
|
@@ -96018,7 +96202,7 @@ async function* verifiedChunkBytes(deps, chunks, signal) {
|
|
|
96018
96202
|
}
|
|
96019
96203
|
let stored;
|
|
96020
96204
|
try {
|
|
96021
|
-
stored = await
|
|
96205
|
+
stored = await retryWhileMissing7(
|
|
96022
96206
|
async () => deps.objectStorage.getObjectBytes(chunk.objectKey)
|
|
96023
96207
|
);
|
|
96024
96208
|
} catch {
|
|
@@ -96102,7 +96286,7 @@ function valueAsUuid(value) {
|
|
|
96102
96286
|
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) {
|
|
96103
96287
|
return value;
|
|
96104
96288
|
}
|
|
96105
|
-
const hex2 =
|
|
96289
|
+
const hex2 = createHash28("sha256").update(value).digest("hex").slice(0, 32);
|
|
96106
96290
|
return `${hex2.slice(0, 8)}-${hex2.slice(8, 12)}-4${hex2.slice(13, 16)}-a${hex2.slice(17, 20)}-${hex2.slice(20, 32)}`;
|
|
96107
96291
|
}
|
|
96108
96292
|
function nonnegativeInteger(value) {
|
|
@@ -96166,7 +96350,7 @@ async function readBoundedBody(request, maxBytes) {
|
|
|
96166
96350
|
return body3;
|
|
96167
96351
|
}
|
|
96168
96352
|
function sha256Hex3(bytes) {
|
|
96169
|
-
return
|
|
96353
|
+
return createHash28("sha256").update(bytes).digest("hex");
|
|
96170
96354
|
}
|
|
96171
96355
|
|
|
96172
96356
|
// src/routes/transcriptions.ts
|
|
@@ -96457,7 +96641,7 @@ function videoGenerationFundingOptions(input) {
|
|
|
96457
96641
|
}
|
|
96458
96642
|
|
|
96459
96643
|
// src/routes/canonical-human-identities.ts
|
|
96460
|
-
import { randomUUID as
|
|
96644
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
96461
96645
|
import {
|
|
96462
96646
|
CanonicalHumanBindingOperationRequest,
|
|
96463
96647
|
CanonicalHumanIdentityMutationResponse,
|
|
@@ -96506,7 +96690,7 @@ import { HTTPException as HTTPException88 } from "hono/http-exception";
|
|
|
96506
96690
|
import { z as z36 } from "zod";
|
|
96507
96691
|
|
|
96508
96692
|
// src/routes/managed-auth-session-sets.ts
|
|
96509
|
-
import { randomUUID as
|
|
96693
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
96510
96694
|
import {
|
|
96511
96695
|
BeginManagedAuthLoginTransactionRequest,
|
|
96512
96696
|
BootstrapManagedAuthSessionSetRequest,
|
|
@@ -96717,7 +96901,7 @@ function registerManagedAuthSessionSetRoutes(app, deps) {
|
|
|
96717
96901
|
app.post("/v1/auth/session-set/transactions", async (context) => {
|
|
96718
96902
|
const body3 = await bodyAs(context, BeginManagedAuthLoginTransactionRequest);
|
|
96719
96903
|
const { authority, actorEpoch } = await requireMutation(context, deps, body3.expectedGeneration);
|
|
96720
|
-
const transactionId =
|
|
96904
|
+
const transactionId = randomUUID14();
|
|
96721
96905
|
const transactionSecret = managedAuthTransactionSecret(
|
|
96722
96906
|
requireSigningSecret(deps),
|
|
96723
96907
|
authority,
|
|
@@ -97938,7 +98122,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
|
|
|
97938
98122
|
return await mutate(context, deps, {
|
|
97939
98123
|
operationType: "link",
|
|
97940
98124
|
...request,
|
|
97941
|
-
operationId: request.operationId ??
|
|
98125
|
+
operationId: request.operationId ?? randomUUID15()
|
|
97942
98126
|
});
|
|
97943
98127
|
});
|
|
97944
98128
|
app.delete(`${base}/login-bindings/:bindingId`, async (context) => {
|
|
@@ -97956,7 +98140,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
|
|
|
97956
98140
|
operationType: "unlink",
|
|
97957
98141
|
bindingId: bindingId(context),
|
|
97958
98142
|
...request,
|
|
97959
|
-
operationId: request.operationId ??
|
|
98143
|
+
operationId: request.operationId ?? randomUUID15()
|
|
97960
98144
|
});
|
|
97961
98145
|
});
|
|
97962
98146
|
app.post(`${base}/login-bindings/:bindingId/recovery`, async (context) => {
|
|
@@ -97974,7 +98158,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
|
|
|
97974
98158
|
operationType: "begin_recovery",
|
|
97975
98159
|
bindingId: bindingId(context),
|
|
97976
98160
|
...request,
|
|
97977
|
-
operationId: request.operationId ??
|
|
98161
|
+
operationId: request.operationId ?? randomUUID15()
|
|
97978
98162
|
});
|
|
97979
98163
|
});
|
|
97980
98164
|
app.post(`${base}/login-bindings/:bindingId/recovery/complete`, async (context) => {
|
|
@@ -97989,7 +98173,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
|
|
|
97989
98173
|
operationType: "recover",
|
|
97990
98174
|
bindingId: bindingId(context),
|
|
97991
98175
|
...request,
|
|
97992
|
-
operationId: request.operationId ??
|
|
98176
|
+
operationId: request.operationId ?? randomUUID15(),
|
|
97993
98177
|
...managed ? { verifiedManagedRecovery: true } : {}
|
|
97994
98178
|
});
|
|
97995
98179
|
});
|
|
@@ -100297,11 +100481,12 @@ async function exactAvailable(providers, providerId, context) {
|
|
|
100297
100481
|
}
|
|
100298
100482
|
|
|
100299
100483
|
// src/integrations/slack-interactions.ts
|
|
100300
|
-
import { createHash as
|
|
100484
|
+
import { createHash as createHash30, createHmac as createHmac10, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
100301
100485
|
import {
|
|
100302
100486
|
approvalIdentifier,
|
|
100303
100487
|
ApproveSlackUserLinkAccessRequest,
|
|
100304
100488
|
DEFAULT_FIRST_PARTY_MCP_TOOLS,
|
|
100489
|
+
resolveWorkspaceSessionToolDefaults,
|
|
100305
100490
|
hasOpenGeniSlackReactionScope,
|
|
100306
100491
|
ListSlackUserLinkAccessRequestsResponse,
|
|
100307
100492
|
PrepareSlackUserLinkAccessRequest,
|
|
@@ -100341,6 +100526,7 @@ import {
|
|
|
100341
100526
|
getOrCreateSlackInteraction,
|
|
100342
100527
|
getLatestSessionModelForSubject,
|
|
100343
100528
|
getSession as getSession11,
|
|
100529
|
+
getSessionByCreateIdempotencyKey,
|
|
100344
100530
|
getSessionEvent as getSessionEvent2,
|
|
100345
100531
|
getSessionHumanInputRequest as getSessionHumanInputRequest2,
|
|
100346
100532
|
childRequiresActionResolutionExists,
|
|
@@ -100400,6 +100586,7 @@ import {
|
|
|
100400
100586
|
acceptSessionUserMessage as acceptSessionUserMessage2,
|
|
100401
100587
|
controlHumanSessionWorkstream as controlHumanSessionWorkstream2,
|
|
100402
100588
|
createSessionForRequest as createSessionForRequest2,
|
|
100589
|
+
getActorNewSessionDefaults,
|
|
100403
100590
|
hasPermission as hasPermission26,
|
|
100404
100591
|
requireAccessContext as requireAccessContext8,
|
|
100405
100592
|
requireAccessGrant as requireAccessGrant45,
|
|
@@ -100775,9 +100962,9 @@ function record4(value) {
|
|
|
100775
100962
|
}
|
|
100776
100963
|
|
|
100777
100964
|
// src/slack-reaction-files.ts
|
|
100778
|
-
import { createHash as
|
|
100965
|
+
import { createHash as createHash29 } from "crypto";
|
|
100779
100966
|
import { completeFileUpload as completeFileUpload5, prepareGeneratedWorkspaceFile as prepareGeneratedWorkspaceFile2 } from "@opengeni/db";
|
|
100780
|
-
import { retryWhileMissing as
|
|
100967
|
+
import { retryWhileMissing as retryWhileMissing8 } from "@opengeni/storage";
|
|
100781
100968
|
var IMPORT_IDENTITY_VERSION = "slack-reaction-image-v1";
|
|
100782
100969
|
var UPLOAD_INTENT_TTL_MS2 = 60 * 6e4;
|
|
100783
100970
|
var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
|
|
@@ -100792,7 +100979,7 @@ async function importSlackReactionImage(dependencies, source, image, ordinal) {
|
|
|
100792
100979
|
if (image.bytes.byteLength < 1 || image.bytes.byteLength > 4 * 1024 * 1024) {
|
|
100793
100980
|
throw new Error("Slack reaction image size is invalid");
|
|
100794
100981
|
}
|
|
100795
|
-
const sha2563 =
|
|
100982
|
+
const sha2563 = createHash29("sha256").update(image.bytes).digest("hex");
|
|
100796
100983
|
const identity2 = slackReactionImageIdentity(source, image.fileId);
|
|
100797
100984
|
const fileId = deterministicUuid(`${identity2}:file`);
|
|
100798
100985
|
const uploadId = deterministicUuid(`${identity2}:upload`);
|
|
@@ -100877,7 +101064,7 @@ function safeSlackImageFilename(value, contentType) {
|
|
|
100877
101064
|
return `${stem}${extension}`;
|
|
100878
101065
|
}
|
|
100879
101066
|
async function assertVisibleSlackImage(storage, objectKey, image, sha2563) {
|
|
100880
|
-
const head = await
|
|
101067
|
+
const head = await retryWhileMissing8(async () => await storage.headObject(objectKey));
|
|
100881
101068
|
assertStoredSlackImage(head, image, sha2563);
|
|
100882
101069
|
}
|
|
100883
101070
|
function assertStoredSlackImage(head, image, sha2563) {
|
|
@@ -100886,7 +101073,7 @@ function assertStoredSlackImage(head, image, sha2563) {
|
|
|
100886
101073
|
}
|
|
100887
101074
|
}
|
|
100888
101075
|
function deterministicUuid(seed) {
|
|
100889
|
-
const bytes =
|
|
101076
|
+
const bytes = createHash29("sha256").update(seed, "utf8").digest().subarray(0, 16);
|
|
100890
101077
|
bytes[6] = (bytes[6] ?? 0) & 15 | 80;
|
|
100891
101078
|
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
100892
101079
|
const hex2 = bytes.toString("hex");
|
|
@@ -101045,7 +101232,7 @@ function slackReactionInboxEntry(payload, bot, settings) {
|
|
|
101045
101232
|
if (!settings.enabled || !event || event.type !== "reaction_added" || item?.type !== "message" || !teamId || !eventId || !userId || userId === bot.botUserId || !reaction || reaction !== settings.emoji || !channelId || !workspaceSlackReactionChannelAllowed(settings, channelId) || !timestamp) {
|
|
101046
101233
|
return null;
|
|
101047
101234
|
}
|
|
101048
|
-
const stableReactionIdentity =
|
|
101235
|
+
const stableReactionIdentity = createHash30("sha256").update([teamId, userId, channelId, timestamp, reaction].join("\n")).digest("hex");
|
|
101049
101236
|
return {
|
|
101050
101237
|
providerEventId: eventId,
|
|
101051
101238
|
providerMessageId: `reaction:${stableReactionIdentity}`,
|
|
@@ -101235,7 +101422,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
101235
101422
|
const prepared = await prepareSlackUserLinkAccessRequest(deps.db, {
|
|
101236
101423
|
accountId: installation.accountId,
|
|
101237
101424
|
workspaceId,
|
|
101238
|
-
tokenDigest:
|
|
101425
|
+
tokenDigest: createHash30("sha256").update(payload.linkToken).digest("hex"),
|
|
101239
101426
|
connectionId: link.connectionId,
|
|
101240
101427
|
slackTeamId: link.slackTeamId,
|
|
101241
101428
|
slackUserId: link.slackUserId,
|
|
@@ -101442,7 +101629,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
101442
101629
|
const prepared = await prepareSlackUserLinkAccessRequest(deps.db, {
|
|
101443
101630
|
accountId: grant.accountId,
|
|
101444
101631
|
workspaceId,
|
|
101445
|
-
tokenDigest:
|
|
101632
|
+
tokenDigest: createHash30("sha256").update(linkToken).digest("hex"),
|
|
101446
101633
|
connectionId: link.connectionId,
|
|
101447
101634
|
slackTeamId: link.slackTeamId,
|
|
101448
101635
|
slackUserId: link.slackUserId,
|
|
@@ -102405,6 +102592,14 @@ async function processSlackInboxEntry(deps, entry2) {
|
|
|
102405
102592
|
);
|
|
102406
102593
|
let session;
|
|
102407
102594
|
try {
|
|
102595
|
+
const defaults = await slackNewSessionDefaults(
|
|
102596
|
+
deps,
|
|
102597
|
+
grant,
|
|
102598
|
+
interaction,
|
|
102599
|
+
`slack:${entry2.connectionId}:${entry2.providerEventId}`
|
|
102600
|
+
);
|
|
102601
|
+
const workspace = await getWorkspace7(deps.db, interaction.workspaceId);
|
|
102602
|
+
const defaultTools = defaults.firstPartyMcpTools ?? resolveWorkspaceSessionToolDefaults(workspace?.settings)?.firstPartyMcpTools;
|
|
102408
102603
|
const prepared = slackInvocationPreparedMessage(
|
|
102409
102604
|
preparedEntry,
|
|
102410
102605
|
preparedAttachments,
|
|
@@ -102415,13 +102610,14 @@ async function processSlackInboxEntry(deps, entry2) {
|
|
|
102415
102610
|
grant,
|
|
102416
102611
|
interaction.workspaceId,
|
|
102417
102612
|
{
|
|
102613
|
+
...defaults,
|
|
102418
102614
|
requestedSessionId: interaction.sessionReservationId,
|
|
102419
102615
|
initialMessage: prepared.entry.text,
|
|
102420
102616
|
...prepared.modelContext ? { modelContext: prepared.modelContext } : {},
|
|
102421
102617
|
instructions: SLACK_SESSION_INSTRUCTIONS,
|
|
102422
|
-
firstPartyMcpTools: slackTaskFirstPartyMcpTools(deps.settings),
|
|
102423
|
-
resources: preparedAttachments.resources,
|
|
102424
|
-
|
|
102618
|
+
firstPartyMcpTools: defaultTools !== void 0 ? allowedFirstPartyMcpToolsForSession4(deps.settings, defaultTools) : slackTaskFirstPartyMcpTools(deps.settings),
|
|
102619
|
+
resources: [...defaults.resources, ...preparedAttachments.resources],
|
|
102620
|
+
...!defaults.model && preferredModel ? { model: preferredModel } : {},
|
|
102425
102621
|
idempotencyKey: `slack:${entry2.connectionId}:${entry2.providerEventId}`,
|
|
102426
102622
|
clientEventId: `slack:${entry2.providerEventId}`
|
|
102427
102623
|
}
|
|
@@ -102842,19 +103038,25 @@ async function processSlackReactionInboxEntry(deps, entry2) {
|
|
|
102842
103038
|
const preparedEntry = slackReactionPreparedEntry(entry2, context, preparedTask);
|
|
102843
103039
|
let session;
|
|
102844
103040
|
try {
|
|
103041
|
+
const defaults = await slackNewSessionDefaults(
|
|
103042
|
+
deps,
|
|
103043
|
+
grant,
|
|
103044
|
+
interaction,
|
|
103045
|
+
`slack-interaction:${interaction.id}`
|
|
103046
|
+
);
|
|
102845
103047
|
session = await createSessionForRequest2(
|
|
102846
103048
|
await withCatalogSettings(deps, grant),
|
|
102847
103049
|
grant,
|
|
102848
103050
|
interaction.workspaceId,
|
|
102849
103051
|
{
|
|
103052
|
+
...defaults,
|
|
102850
103053
|
requestedSessionId: interaction.sessionReservationId,
|
|
102851
103054
|
initialMessage: preparedEntry.text,
|
|
102852
103055
|
instructions: SLACK_SESSION_INSTRUCTIONS,
|
|
102853
|
-
//
|
|
102854
|
-
//
|
|
102855
|
-
|
|
102856
|
-
|
|
102857
|
-
...preferredModel ? { model: preferredModel } : {},
|
|
103056
|
+
// Reaction context stays bounded; ordinary tools follow the same saved
|
|
103057
|
+
// selection/workspace defaults as the website, without adding Slack tools.
|
|
103058
|
+
resources: [...defaults.resources, ...preparedTask.resources],
|
|
103059
|
+
...!defaults.model && preferredModel ? { model: preferredModel } : {},
|
|
102858
103060
|
// Every reaction entry converging on this route must use the same create
|
|
102859
103061
|
// key. This closes the same-owner multi-event race while the owner check
|
|
102860
103062
|
// above prevents a different subject from winning creation authority.
|
|
@@ -102904,6 +103106,35 @@ function slackReactionPreparedEntry(entry2, context, prepared) {
|
|
|
102904
103106
|
text: slackReactionTaskText(context, prepared)
|
|
102905
103107
|
};
|
|
102906
103108
|
}
|
|
103109
|
+
async function slackNewSessionDefaults(deps, grant, interaction, createKey) {
|
|
103110
|
+
const pending = await getSessionByCreateIdempotencyKey(
|
|
103111
|
+
deps.db,
|
|
103112
|
+
interaction.workspaceId,
|
|
103113
|
+
createKey
|
|
103114
|
+
);
|
|
103115
|
+
if (!pending) return getActorNewSessionDefaults(deps, grant, interaction.workspaceId);
|
|
103116
|
+
if (pending.id !== interaction.sessionReservationId || interaction.owningSubjectId !== grant.subjectId || pending.createdBy.kind !== "subject" || pending.createdBy.subjectId !== grant.subjectId) {
|
|
103117
|
+
throw new SlackInteractionPermanentError("slack_session_create_identity_mismatch");
|
|
103118
|
+
}
|
|
103119
|
+
return {
|
|
103120
|
+
model: pending.model,
|
|
103121
|
+
reasoningEffort: pending.reasoningEffort,
|
|
103122
|
+
latencyMode: pending.latencyMode,
|
|
103123
|
+
resources: pending.resources.filter((resource) => resource.kind === "repository"),
|
|
103124
|
+
...pending.toolPolicy.mode === "explicit" ? { tools: pending.tools } : {
|
|
103125
|
+
excludedMcpServerIds: pending.toolPolicy.excludedMcpServerIds
|
|
103126
|
+
},
|
|
103127
|
+
firstPartyMcpTools: pending.firstPartyMcpTools,
|
|
103128
|
+
...pending.firstPartyMcpPermissions ? { firstPartyMcpPermissions: pending.firstPartyMcpPermissions } : {},
|
|
103129
|
+
variableSetIds: pending.variableSetIds,
|
|
103130
|
+
...pending.rigId ? { rigId: pending.rigId } : {},
|
|
103131
|
+
sandboxBackend: pending.sandboxBackend,
|
|
103132
|
+
...pending.sandboxBackend === "selfhosted" && pending.activeSandboxId ? {
|
|
103133
|
+
targetSandboxId: pending.activeSandboxId,
|
|
103134
|
+
...pending.workingDir ? { workingDir: pending.workingDir } : {}
|
|
103135
|
+
} : {}
|
|
103136
|
+
};
|
|
103137
|
+
}
|
|
102907
103138
|
async function remountSlackReactionTaskForSession(deps, workspaceId, sessionId, prepared) {
|
|
102908
103139
|
if (prepared.attachments.length === 0) return prepared;
|
|
102909
103140
|
const session = await getSession11(deps.db, workspaceId, sessionId);
|
|
@@ -104335,7 +104566,7 @@ function normalizedBlockActionInteraction(payload) {
|
|
|
104335
104566
|
if (!teamId || !userId || !channelId || !messageTs || !actionTs || !actionId || !SLACK_BLOCK_ACTION_IDS.has(actionId) || !handleId || !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(handleId) || !Array.isArray(payload.actions) || payload.actions.length !== 1) {
|
|
104336
104567
|
throw new HTTPException95(400, { message: "invalid Slack block action" });
|
|
104337
104568
|
}
|
|
104338
|
-
const identity2 =
|
|
104569
|
+
const identity2 = createHash30("sha256").update([teamId, userId, channelId, messageTs, actionTs, actionId, handleId].join("\n")).digest("hex");
|
|
104339
104570
|
return {
|
|
104340
104571
|
providerEventId: `block:${identity2}`,
|
|
104341
104572
|
providerMessageId: `block:${identity2}`,
|
|
@@ -104600,7 +104831,7 @@ function usesPrivateBotDm(interaction, entry2) {
|
|
|
104600
104831
|
return isDirectMessageShortcut(entry2) || interaction.visibility === "private" && entry2.triggerKind !== "dm";
|
|
104601
104832
|
}
|
|
104602
104833
|
function deterministicUuid2(value) {
|
|
104603
|
-
const bytes =
|
|
104834
|
+
const bytes = createHash30("sha256").update(value).digest().subarray(0, 16);
|
|
104604
104835
|
bytes[6] = bytes[6] & 15 | 80;
|
|
104605
104836
|
bytes[8] = bytes[8] & 63 | 128;
|
|
104606
104837
|
const hex2 = bytes.toString("hex");
|
|
@@ -104825,7 +105056,7 @@ function createAppComposition(deps) {
|
|
|
104825
105056
|
}) : deps.transcriptionSegmenter;
|
|
104826
105057
|
const routeDeps = {
|
|
104827
105058
|
...deps,
|
|
104828
|
-
resolveCatalogSettings: () =>
|
|
105059
|
+
resolveCatalogSettings: () => resolveCatalogSettings2(deps.db, deps.settings),
|
|
104829
105060
|
observability,
|
|
104830
105061
|
githubStateSecret: deps.githubStateSecret ?? deps.settings.githubAppManifestStateSecret ?? crypto.randomUUID(),
|
|
104831
105062
|
managedAuth,
|
|
@@ -105255,9 +105486,9 @@ function createAppComposition(deps) {
|
|
|
105255
105486
|
registerMcpOAuthRoutes(app, routeDeps);
|
|
105256
105487
|
app.get("/v1/config/client", async (c) => {
|
|
105257
105488
|
c.header("cache-control", "no-store");
|
|
105258
|
-
const resolvedCatalog = await
|
|
105489
|
+
const resolvedCatalog = await resolveCatalogSettings2(deps.db, deps.settings);
|
|
105259
105490
|
const baseCatalogSettings = resolvedCatalog.settings;
|
|
105260
|
-
const codexCatalogSettings = baseCatalogSettings.codexSubscriptionEnabled ?
|
|
105491
|
+
const codexCatalogSettings = baseCatalogSettings.codexSubscriptionEnabled ? withCodexCatalogProvider3(baseCatalogSettings) : baseCatalogSettings;
|
|
105261
105492
|
const catalogSettings = baseCatalogSettings.supergrokSubscriptionEnabled ? withXaiSubscriptionCatalogProvider3(codexCatalogSettings) : codexCatalogSettings;
|
|
105262
105493
|
return c.json(
|
|
105263
105494
|
ClientConfig.parse({
|
|
@@ -105270,7 +105501,7 @@ function createAppComposition(deps) {
|
|
|
105270
105501
|
// union of the built-in allow-list and every registry provider's models, in
|
|
105271
105502
|
// selection order (default model first); project each to the client-safe
|
|
105272
105503
|
// provider-blind ClientModel shape (execution topology remains server-side).
|
|
105273
|
-
models:
|
|
105504
|
+
models: configuredModels4(catalogSettings).map(projectClientModel),
|
|
105274
105505
|
defaultReasoningEffort: deps.settings.openaiReasoningEffort,
|
|
105275
105506
|
allowedReasoningEfforts: configuredAllowedReasoningEfforts(deps.settings),
|
|
105276
105507
|
defaultSandboxBackend: deps.settings.sandboxBackend,
|
|
@@ -105952,7 +106183,7 @@ function readinessChecks(deps) {
|
|
|
105952
106183
|
} else {
|
|
105953
106184
|
await deps.db.execute(dbSql`select 1`);
|
|
105954
106185
|
}
|
|
105955
|
-
await
|
|
106186
|
+
await resolveCatalogSettings2(deps.db, deps.settings);
|
|
105956
106187
|
},
|
|
105957
106188
|
nats: async () => {
|
|
105958
106189
|
requireSessionEventDurableFanoutCapability2(deps.bus);
|
|
@@ -106882,4 +107113,4 @@ export {
|
|
|
106882
107113
|
withDefaultEnabledCapabilityMcpTools,
|
|
106883
107114
|
workflowIdForSession4 as workflowIdForSession
|
|
106884
107115
|
};
|
|
106885
|
-
//# sourceMappingURL=chunk-
|
|
107116
|
+
//# sourceMappingURL=chunk-24C5LPNE.js.map
|