@opengeni/worker-bundle 3.1.2 → 3.2.2
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/activities/agent-turn/secret-resolver.d.ts +4 -2
- package/dist/activities/types.d.ts +2 -1
- package/dist/{activities-control-ROJJNNTJ.js → activities-control-LC7WXEIX.js} +4 -3
- package/dist/{activities-control-ROJJNNTJ.js.map → activities-control-LC7WXEIX.js.map} +1 -1
- package/dist/{activities-turn-4SWYWKI5.js → activities-turn-PEDPUZI4.js} +13 -4
- package/dist/activities-turn-PEDPUZI4.js.map +1 -0
- package/dist/{chunk-6SHXF4SU.js → chunk-436TOEBL.js} +10 -3
- package/dist/chunk-436TOEBL.js.map +1 -0
- package/dist/chunk-K225DMA7.js +85 -0
- package/dist/chunk-K225DMA7.js.map +1 -0
- package/dist/{chunk-MVESOYFC.js → chunk-O7HT4LHX.js} +4 -1
- package/dist/{chunk-MVESOYFC.js.map → chunk-O7HT4LHX.js.map} +1 -1
- package/dist/external-vault-providers.d.ts +29 -0
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/dist/{sandbox-lease-BJYU72N3.js → sandbox-lease-F47EDHHY.js} +2 -2
- package/dist/workflow-bundle.js +1 -1
- package/package.json +27 -24
- package/src/activities/agent-turn/run.ts +6 -0
- package/src/activities/agent-turn/secret-resolver.ts +6 -0
- package/src/activities/sandbox-lease.ts +3 -0
- package/src/activities/types.ts +5 -1
- package/src/activity-services.ts +9 -1
- package/src/external-vault-providers.ts +136 -0
- package/src/index.ts +7 -1
- package/dist/activities-turn-4SWYWKI5.js.map +0 -1
- package/dist/chunk-6SHXF4SU.js.map +0 -1
- /package/dist/{sandbox-lease-BJYU72N3.js.map → sandbox-lease-F47EDHHY.js.map} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/worker-bundle",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.2",
|
|
4
4
|
"description": "Opengeni worker entry and reusable embedded lifecycle, shipped with a release-coherent pre-bundled Temporal workflow artifact.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -54,30 +54,33 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@1password/sdk": "0.5.0",
|
|
57
|
+
"@keeper-security/secrets-manager-core": "17.6.0",
|
|
57
58
|
"@llamaindex/liteparse": "2.14.2",
|
|
58
|
-
"@opengeni/agent-proto": "3.
|
|
59
|
-
"@opengeni/capabilities": "3.
|
|
60
|
-
"@opengeni/codemode": "3.
|
|
61
|
-
"@opengeni/codex": "3.
|
|
62
|
-
"@opengeni/config": "3.
|
|
63
|
-
"@opengeni/contracts": "3.
|
|
64
|
-
"@opengeni/core": "3.
|
|
65
|
-
"@opengeni/db": "3.
|
|
66
|
-
"@opengeni/documents": "3.
|
|
67
|
-
"@opengeni/events": "3.
|
|
68
|
-
"@opengeni/github": "3.
|
|
69
|
-
"@opengeni/interaction": "3.
|
|
70
|
-
"@opengeni/jev": "3.
|
|
71
|
-
"@opengeni/network": "3.
|
|
72
|
-
"@opengeni/observability": "3.
|
|
73
|
-
"@opengeni/runtime": "3.
|
|
74
|
-
"@opengeni/sdk": "3.
|
|
75
|
-
"@opengeni/storage": "3.
|
|
76
|
-
"@opengeni/subscriptions": "3.
|
|
77
|
-
"@opengeni/tool-gateway": "3.
|
|
78
|
-
"@opengeni/vaults": "3.
|
|
79
|
-
"@opengeni/vaults-
|
|
80
|
-
"@opengeni/
|
|
59
|
+
"@opengeni/agent-proto": "3.2.2",
|
|
60
|
+
"@opengeni/capabilities": "3.2.2",
|
|
61
|
+
"@opengeni/codemode": "3.2.2",
|
|
62
|
+
"@opengeni/codex": "3.2.2",
|
|
63
|
+
"@opengeni/config": "3.2.2",
|
|
64
|
+
"@opengeni/contracts": "3.2.2",
|
|
65
|
+
"@opengeni/core": "3.2.2",
|
|
66
|
+
"@opengeni/db": "3.2.2",
|
|
67
|
+
"@opengeni/documents": "3.2.2",
|
|
68
|
+
"@opengeni/events": "3.2.2",
|
|
69
|
+
"@opengeni/github": "3.2.2",
|
|
70
|
+
"@opengeni/interaction": "3.2.2",
|
|
71
|
+
"@opengeni/jev": "3.2.2",
|
|
72
|
+
"@opengeni/network": "3.2.2",
|
|
73
|
+
"@opengeni/observability": "3.2.2",
|
|
74
|
+
"@opengeni/runtime": "3.2.2",
|
|
75
|
+
"@opengeni/sdk": "3.2.2",
|
|
76
|
+
"@opengeni/storage": "3.2.2",
|
|
77
|
+
"@opengeni/subscriptions": "3.2.2",
|
|
78
|
+
"@opengeni/tool-gateway": "3.2.2",
|
|
79
|
+
"@opengeni/vaults": "3.2.2",
|
|
80
|
+
"@opengeni/vaults-keeper": "3.2.2",
|
|
81
|
+
"@opengeni/vaults-onepassword": "3.2.2",
|
|
82
|
+
"@opengeni/vaults-protonpass": "3.2.2",
|
|
83
|
+
"@opengeni/xai-subscription": "3.2.2",
|
|
81
84
|
"@temporalio/activity": "^1.17.0",
|
|
82
85
|
"@temporalio/client": "^1.17.0",
|
|
83
86
|
"@temporalio/worker": "^1.17.0",
|
|
@@ -1611,6 +1611,12 @@ export function createRunAgentTurnActivity(services: () => Promise<ActivityServi
|
|
|
1611
1611
|
subjectId: turn.initiatingHumanSubjectId ?? credentialSubjectId ?? null,
|
|
1612
1612
|
hostVaultProvider: connectionCredentials?.vaultProvider,
|
|
1613
1613
|
onePasswordVaultProvider: resolvedServices.onePasswordVaultProvider,
|
|
1614
|
+
externalVaultProviders: resolvedServices.externalVaultProviders ?? null,
|
|
1615
|
+
executionContext: {
|
|
1616
|
+
sessionId: input.sessionId,
|
|
1617
|
+
turnId: turn.id,
|
|
1618
|
+
attemptId: input.attemptId,
|
|
1619
|
+
},
|
|
1614
1620
|
});
|
|
1615
1621
|
const toolRuntime = await prepareTurnToolRuntime({
|
|
1616
1622
|
vaultAccess,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
createSecretResolver,
|
|
16
16
|
createWorkspaceVaultProviderRegistry,
|
|
17
17
|
type OnePasswordVaultProviderFactory,
|
|
18
|
+
type ExternalVaultProviderFactories,
|
|
18
19
|
} from "@opengeni/core";
|
|
19
20
|
import { listVaultsForSubject, type Database } from "@opengeni/db";
|
|
20
21
|
import {
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
type ProviderCallBudget,
|
|
23
24
|
type VaultProvider,
|
|
24
25
|
type VaultProviderRegistry,
|
|
26
|
+
type VaultProviderAuthority,
|
|
25
27
|
} from "@opengeni/vaults";
|
|
26
28
|
|
|
27
29
|
/**
|
|
@@ -49,6 +51,8 @@ export function createAttemptVaultAccess(input: {
|
|
|
49
51
|
subjectId: string | null;
|
|
50
52
|
hostVaultProvider: VaultProvider | null | undefined;
|
|
51
53
|
onePasswordVaultProvider: OnePasswordVaultProviderFactory | null | undefined;
|
|
54
|
+
externalVaultProviders?: ExternalVaultProviderFactories | null;
|
|
55
|
+
executionContext?: Pick<VaultProviderAuthority, "sessionId" | "turnId" | "attemptId" | "siteId">;
|
|
52
56
|
}): AttemptVaultAccess {
|
|
53
57
|
return {
|
|
54
58
|
providers: createWorkspaceVaultProviderRegistry({
|
|
@@ -58,6 +62,8 @@ export function createAttemptVaultAccess(input: {
|
|
|
58
62
|
subjectId: input.subjectId,
|
|
59
63
|
hostVaultProvider: input.hostVaultProvider ?? null,
|
|
60
64
|
onePasswordVaultProvider: input.onePasswordVaultProvider ?? null,
|
|
65
|
+
externalVaultProviders: input.externalVaultProviders ?? null,
|
|
66
|
+
...(input.executionContext ? { executionContext: input.executionContext } : {}),
|
|
61
67
|
}),
|
|
62
68
|
attemptBudget: createProviderCallBudget(VAULT_LIMITS.providerReadsPerAttempt),
|
|
63
69
|
};
|
|
@@ -4105,6 +4105,9 @@ async function terminateDrainableBox(
|
|
|
4105
4105
|
minIntervalMs: 0,
|
|
4106
4106
|
pointInTimeCapture: providerWorkspaceCaptureIsPointInTime(backend, lease.resumeState),
|
|
4107
4107
|
deadlineMandatoryCaptureLeadMs: sandboxDeadlineMandatoryCaptureLeadMs(settings),
|
|
4108
|
+
// An unknown-outcome setup request of a closed attempt never settles
|
|
4109
|
+
// on a live box; after the idle grace it no longer pins the drain.
|
|
4110
|
+
abandonedSetupCaptureAfterMs: Math.max(settings.sandboxIdleGraceMs, 60_000),
|
|
4108
4111
|
providerReplaySafe: capturePolicy?.takeover === "same_request",
|
|
4109
4112
|
takeoverSafe: capturePolicy !== null && capturePolicy.takeover !== "exclusive",
|
|
4110
4113
|
});
|
package/src/activities/types.ts
CHANGED
|
@@ -18,7 +18,10 @@ import type { Observability } from "@opengeni/observability";
|
|
|
18
18
|
import type { OpenGeniRuntime } from "@opengeni/runtime";
|
|
19
19
|
import type { ObjectStorage } from "@opengeni/storage";
|
|
20
20
|
import type { VaultConnectionCredentialsPort } from "@opengeni/vaults";
|
|
21
|
-
import type {
|
|
21
|
+
import type {
|
|
22
|
+
ExternalVaultProviderFactories,
|
|
23
|
+
OnePasswordVaultProviderFactory,
|
|
24
|
+
} from "@opengeni/core";
|
|
22
25
|
|
|
23
26
|
// Signal (start-if-needed) a session's Temporal workflow so a queued turn it
|
|
24
27
|
// cannot otherwise observe gets claimed. Used to wake a PARENT session's
|
|
@@ -141,6 +144,7 @@ export type SharedActivityServices = {
|
|
|
141
144
|
* `@opengeni/vaults-onepassword`); null leaves 1Password vaults unavailable.
|
|
142
145
|
*/
|
|
143
146
|
onePasswordVaultProvider?: OnePasswordVaultProviderFactory | null;
|
|
147
|
+
externalVaultProviders?: ExternalVaultProviderFactories | null;
|
|
144
148
|
/** Standalone, default-off personal GitHub smart-HTTP broker consumer. */
|
|
145
149
|
personalGitHubCredentials?: ConnectionCredentialsPort["gitCredentials"] | null;
|
|
146
150
|
};
|
package/src/activity-services.ts
CHANGED
|
@@ -12,13 +12,14 @@ import {
|
|
|
12
12
|
} from "@opengeni/db";
|
|
13
13
|
import { createNatsEventBus } from "@opengeni/events";
|
|
14
14
|
import { createObservability } from "@opengeni/observability";
|
|
15
|
-
import { resolveCatalogSettings } from "@opengeni/core";
|
|
15
|
+
import { createRemoteExternalVaultFactories, resolveCatalogSettings } from "@opengeni/core";
|
|
16
16
|
import { createObjectStorage } from "@opengeni/storage";
|
|
17
17
|
import type { ActivityDependencies, SharedActivityServices } from "./activities/types";
|
|
18
18
|
import { observabilityEventBusOptions } from "./observability-metrics";
|
|
19
19
|
import { buildPersonalGitHubGitCredentials } from "./personal-github-git-credentials";
|
|
20
20
|
import { createStandaloneConnectionCredentialsPort } from "./pr-review-credentials";
|
|
21
21
|
import { loadOnePasswordVaultProvider } from "./onepassword-vault-provider";
|
|
22
|
+
import { createNativeExternalVaultFactories } from "./external-vault-providers";
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Build the dependency graph common to both worker roles exactly once.
|
|
@@ -92,6 +93,13 @@ export function createSharedActivityServices(
|
|
|
92
93
|
dependencies.onePasswordVaultProvider === undefined
|
|
93
94
|
? loadOnePasswordVaultProvider
|
|
94
95
|
: dependencies.onePasswordVaultProvider,
|
|
96
|
+
externalVaultProviders:
|
|
97
|
+
dependencies.externalVaultProviders === undefined
|
|
98
|
+
? {
|
|
99
|
+
...createRemoteExternalVaultFactories(settings),
|
|
100
|
+
...createNativeExternalVaultFactories(settings),
|
|
101
|
+
}
|
|
102
|
+
: dependencies.externalVaultProviders,
|
|
95
103
|
};
|
|
96
104
|
})();
|
|
97
105
|
return await servicesPromise;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { Settings } from "@opengeni/config";
|
|
2
|
+
import type {
|
|
3
|
+
ExternalVaultProviderFactories,
|
|
4
|
+
ExternalVaultProviderFactory,
|
|
5
|
+
StoredVaultProviderCredentials,
|
|
6
|
+
} from "@opengeni/core";
|
|
7
|
+
import { pinnedFetch, type PinnedFetchOptions } from "@opengeni/network";
|
|
8
|
+
import { VaultProviderError } from "@opengeni/vaults";
|
|
9
|
+
import type { KeeperRuntimeOptions } from "@opengeni/vaults-keeper";
|
|
10
|
+
import type { ProtonPassProviderPool } from "@opengeni/vaults-protonpass";
|
|
11
|
+
|
|
12
|
+
/** Test seams only; production passes nothing. */
|
|
13
|
+
export type NativeExternalVaultOptions = {
|
|
14
|
+
keeper?: Pick<KeeperRuntimeOptions, "queryFunction" | "fetchFile" | "sdk">;
|
|
15
|
+
/** Applies when this call creates the pool for its CLI path. */
|
|
16
|
+
protonpass?: { stateRoot?: string; hostEnv?: Readonly<Record<string, string | undefined>> };
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Native external vault adapters that run inside this server: Keeper Secrets
|
|
21
|
+
* Manager always, Proton Pass only when the operator installed `pass-cli`
|
|
22
|
+
* (`OPENGENI_PROTON_PASS_CLI_PATH`). Both packages load through `import()`
|
|
23
|
+
* on first use (packages/vaults-keeper/test/import-guard.test.ts). Keep this
|
|
24
|
+
* file identical to apps/api/src/integrations/external-vault-providers.ts.
|
|
25
|
+
*/
|
|
26
|
+
export function createNativeExternalVaultFactories(
|
|
27
|
+
settings: Settings,
|
|
28
|
+
options: NativeExternalVaultOptions = {},
|
|
29
|
+
): ExternalVaultProviderFactories {
|
|
30
|
+
const factories: ExternalVaultProviderFactories = {
|
|
31
|
+
keeper: keeperFactory(settings, options.keeper ?? {}),
|
|
32
|
+
};
|
|
33
|
+
const cliPath = settings.protonPassCliPath;
|
|
34
|
+
if (cliPath) factories.protonpass = protonPassFactory(cliPath, options.protonpass ?? {});
|
|
35
|
+
return factories;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Logs out every pooled Proton Pass CLI session and wipes its state (graceful shutdown). */
|
|
39
|
+
export async function closeNativeExternalVaultProviders(): Promise<void> {
|
|
40
|
+
const pools = [...protonPools.values()];
|
|
41
|
+
protonPools.clear();
|
|
42
|
+
await Promise.all(pools.map(async (pool) => (await pool.catch(() => null))?.close()));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function mismatch(): never {
|
|
46
|
+
throw new VaultProviderError(
|
|
47
|
+
"provider_unavailable",
|
|
48
|
+
"The configured adapter does not match this connection.",
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The fetch every Keeper request and file download uses: DNS-pinned and
|
|
54
|
+
* policy-checked (no private or special-use targets). The adapter adds
|
|
55
|
+
* HTTPS-only, no redirects, deadlines, size bounds and the caller's abort.
|
|
56
|
+
*/
|
|
57
|
+
export function nativeKeeperFetch(
|
|
58
|
+
settings: Settings,
|
|
59
|
+
pinned: Pick<PinnedFetchOptions, "dnsLookup" | "fetchImpl" | "agentFactory"> = {},
|
|
60
|
+
) {
|
|
61
|
+
return (input: string | URL, init: RequestInit) =>
|
|
62
|
+
pinnedFetch(input, init, settings, {
|
|
63
|
+
...pinned,
|
|
64
|
+
label: "Keeper Secrets Manager",
|
|
65
|
+
requireHttpsOutsideLocalTest: true,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function keeperFactory(
|
|
70
|
+
settings: Settings,
|
|
71
|
+
seams: NonNullable<NativeExternalVaultOptions["keeper"]>,
|
|
72
|
+
): ExternalVaultProviderFactory {
|
|
73
|
+
const fetch = nativeKeeperFetch(settings);
|
|
74
|
+
return async (input) => {
|
|
75
|
+
const credentials = input.credentials;
|
|
76
|
+
if (credentials.provider !== "keeper") mismatch();
|
|
77
|
+
const persist = input.persistCredentials;
|
|
78
|
+
const { openKeeperConnection } = await import("@opengeni/vaults-keeper");
|
|
79
|
+
const opened = await openKeeperConnection({
|
|
80
|
+
credentials:
|
|
81
|
+
"oneTimeToken" in credentials
|
|
82
|
+
? {
|
|
83
|
+
oneTimeToken: credentials.oneTimeToken,
|
|
84
|
+
...(credentials.hostname ? { hostname: credentials.hostname } : {}),
|
|
85
|
+
}
|
|
86
|
+
: { configuration: credentials.configuration },
|
|
87
|
+
// Without it openKeeperConnection refuses: a redeemed token or rotated
|
|
88
|
+
// key must never live only in memory.
|
|
89
|
+
...(persist
|
|
90
|
+
? {
|
|
91
|
+
persistConfiguration: (configuration: Record<string, string>) =>
|
|
92
|
+
persist({ provider: "keeper", configuration }),
|
|
93
|
+
}
|
|
94
|
+
: {}),
|
|
95
|
+
...(input.operations ? { operations: input.operations } : {}),
|
|
96
|
+
// Cancels a pending bootstrap; a stored configuration opens without a request.
|
|
97
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
98
|
+
fetch,
|
|
99
|
+
...seams,
|
|
100
|
+
});
|
|
101
|
+
const stored: StoredVaultProviderCredentials = {
|
|
102
|
+
provider: "keeper",
|
|
103
|
+
configuration: opened.configuration,
|
|
104
|
+
};
|
|
105
|
+
return { provider: opened.provider, credentials: stored };
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** One pool per CLI path per process, so repeated factory creation never leaks sessions. */
|
|
110
|
+
const protonPools = new Map<string, Promise<ProtonPassProviderPool>>();
|
|
111
|
+
|
|
112
|
+
function protonPassFactory(
|
|
113
|
+
binaryPath: string,
|
|
114
|
+
seams: NonNullable<NativeExternalVaultOptions["protonpass"]>,
|
|
115
|
+
): ExternalVaultProviderFactory {
|
|
116
|
+
return async (input) => {
|
|
117
|
+
const credentials = input.credentials;
|
|
118
|
+
if (credentials.provider !== "protonpass") mismatch();
|
|
119
|
+
let pool = protonPools.get(binaryPath);
|
|
120
|
+
if (!pool) {
|
|
121
|
+
pool = import("@opengeni/vaults-protonpass").then(({ createProtonPassProviderPool }) =>
|
|
122
|
+
createProtonPassProviderPool({ ...seams, binaryPath }),
|
|
123
|
+
);
|
|
124
|
+
protonPools.set(binaryPath, pool);
|
|
125
|
+
pool.catch(() => protonPools.delete(binaryPath));
|
|
126
|
+
}
|
|
127
|
+
// Sessions are scoped to the connection, so two connections never share
|
|
128
|
+
// CLI state even with the same token. Without a connection id (a setup
|
|
129
|
+
// probe) the provider gets an isolated session of its own.
|
|
130
|
+
const provider = (await pool).provider(credentials.token, {
|
|
131
|
+
...(input.connectionId === undefined ? {} : { connectionId: input.connectionId }),
|
|
132
|
+
...(input.operations ? { operations: input.operations } : {}),
|
|
133
|
+
});
|
|
134
|
+
return { provider, credentials: { provider: "protonpass", token: credentials.token } };
|
|
135
|
+
};
|
|
136
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -42,6 +42,7 @@ import { fileURLToPath } from "node:url";
|
|
|
42
42
|
import type { createControlActivities } from "./activities-control";
|
|
43
43
|
import type { createTurnActivities } from "./activities-turn";
|
|
44
44
|
import type { ActivityDependencies } from "./activities/types";
|
|
45
|
+
import { closeNativeExternalVaultProviders } from "./external-vault-providers";
|
|
45
46
|
import type {
|
|
46
47
|
InspectSessionAttemptActivity,
|
|
47
48
|
SignalCodexCapacityWorkflow,
|
|
@@ -1129,7 +1130,12 @@ export async function startWorker() {
|
|
|
1129
1130
|
},
|
|
1130
1131
|
});
|
|
1131
1132
|
} finally {
|
|
1132
|
-
await Promise.allSettled([
|
|
1133
|
+
await Promise.allSettled([
|
|
1134
|
+
closeNativeExternalVaultProviders(),
|
|
1135
|
+
bus?.close(),
|
|
1136
|
+
readinessDbClient.close(),
|
|
1137
|
+
dbClient.close(),
|
|
1138
|
+
]);
|
|
1133
1139
|
disposeUnhandledRejectionBoundary();
|
|
1134
1140
|
}
|
|
1135
1141
|
}
|