Skip to content

Commit 4ea3583

Browse files
authored
Fail early on self-rpc (#2177)
* fail early on self-rpc * update
1 parent 665daa9 commit 4ea3583

File tree

18 files changed

+1815
-7
lines changed

18 files changed

+1815
-7
lines changed

golem-worker-executor/src/durable_host/wasm_rpc/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,16 @@ impl<Ctx: WorkerCtx> HostWasmRpc for DurableWorkerCtx<Ctx> {
8484
let args = self.get_arguments().await?;
8585
let env = self.get_environment().await?;
8686
let wasi_config_vars = self.wasi_config_vars();
87+
let own_worker_id = self.owned_worker_id().clone();
8788

8889
let entry = self.table().get(&self_)?;
8990
let payload = entry.payload.downcast_ref::<WasmRpcEntryPayload>().unwrap();
9091
let remote_worker_id = payload.remote_worker_id().clone();
92+
93+
if remote_worker_id == own_worker_id {
94+
return Err(anyhow!("RPC calls to the same agent are not supported"));
95+
}
96+
9197
let connection_span_id = payload.span_id().clone();
9298

9399
Self::add_self_parameter_if_needed(&mut function_params, payload);
@@ -220,10 +226,16 @@ impl<Ctx: WorkerCtx> HostWasmRpc for DurableWorkerCtx<Ctx> {
220226
let args = self.get_arguments().await?;
221227
let env = self.get_environment().await?;
222228
let wasi_config_vars = self.wasi_config_vars();
229+
let own_worker_id = self.owned_worker_id().clone();
223230

224231
let entry = self.table().get(&self_)?;
225232
let payload = entry.payload.downcast_ref::<WasmRpcEntryPayload>().unwrap();
226233
let remote_worker_id = payload.remote_worker_id().clone();
234+
235+
if remote_worker_id == own_worker_id {
236+
return Err(anyhow!("RPC calls to the same agent are not supported"));
237+
}
238+
227239
let connection_span_id = payload.span_id().clone();
228240

229241
Self::add_self_parameter_if_needed(&mut function_params, payload);
@@ -325,6 +337,7 @@ impl<Ctx: WorkerCtx> HostWasmRpc for DurableWorkerCtx<Ctx> {
325337
let args = self.get_arguments().await?;
326338
let env = self.get_environment().await?;
327339
let wasi_config_vars = self.wasi_config_vars();
340+
let own_worker_id = self.owned_worker_id().clone();
328341

329342
let begin_index = self
330343
.begin_function(&DurableFunctionType::WriteRemote)
@@ -333,6 +346,11 @@ impl<Ctx: WorkerCtx> HostWasmRpc for DurableWorkerCtx<Ctx> {
333346
let entry = self.table().get(&this)?;
334347
let payload = entry.payload.downcast_ref::<WasmRpcEntryPayload>().unwrap();
335348
let remote_worker_id = payload.remote_worker_id().clone();
349+
350+
if remote_worker_id == own_worker_id {
351+
return Err(anyhow!("RPC calls to the same agent are not supported"));
352+
}
353+
336354
let connection_span_id = payload.span_id().clone();
337355

338356
Self::add_self_parameter_if_needed(&mut function_params, payload);

golem-worker-executor/tests/agent.rs

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,63 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use crate::common::{start, TestContext};
1516
use crate::{LastUniqueId, Tracing, WorkerExecutorTestDependencies};
16-
use golem_wasm_ast::analysis::wit_parser::SharedAnalysedTypeResolve;
17-
use test_r::inherit_test_dep;
17+
use assert2::assert;
18+
use assert2::let_assert;
19+
use golem_api_grpc::proto::golem::worker::v1::worker_error::Error;
20+
use golem_api_grpc::proto::golem::worker::v1::{
21+
worker_execution_error, InvocationFailed, WorkerExecutionError,
22+
};
23+
use golem_api_grpc::proto::golem::worker::{UnknownError, WorkerError};
24+
use golem_test_framework::config::TestDependencies;
25+
use golem_test_framework::dsl::TestDslUnsafe;
26+
use test_r::{inherit_test_dep, test};
1827

1928
inherit_test_dep!(WorkerExecutorTestDependencies);
2029
inherit_test_dep!(LastUniqueId);
2130
inherit_test_dep!(Tracing);
22-
inherit_test_dep!(
23-
#[tagged_as("golem_host")]
24-
SharedAnalysedTypeResolve
25-
);
31+
32+
#[test]
33+
#[tracing::instrument]
34+
async fn agent_self_rpc_is_not_allowed(
35+
last_unique_id: &LastUniqueId,
36+
deps: &WorkerExecutorTestDependencies,
37+
_tracing: &Tracing,
38+
) {
39+
let context = TestContext::new(last_unique_id);
40+
let executor = start(deps, &context).await.unwrap().into_admin().await;
41+
42+
let component_id = executor.component("golem_it_agent_self_rpc").store().await;
43+
let worker_id = executor
44+
.start_worker(&component_id, "self-rpc-agent(\"worker-name\")")
45+
.await;
46+
47+
let result = executor
48+
.invoke_and_await(
49+
&worker_id,
50+
"golem-it:agent-self-rpc/self-rpc-agent.{self-rpc}",
51+
vec![],
52+
)
53+
.await;
54+
55+
let_assert!(
56+
Err(Error::InternalError(WorkerExecutionError {
57+
error: Some(worker_execution_error::Error::InvocationFailed(
58+
InvocationFailed {
59+
error: Some(WorkerError {
60+
error: Some(
61+
golem_api_grpc::proto::golem::worker::worker_error::Error::UnknownError(
62+
UnknownError {
63+
details: error_details
64+
}
65+
)
66+
)
67+
}),
68+
..
69+
}
70+
))
71+
})) = result
72+
);
73+
assert!(error_details.contains("RPC calls to the same agent are not supported"));
74+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/dist
2+
/golem-temp
3+
/node_modules
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Schema for IDEA:
2+
# $schema: https://schema.golem.cloud/app/golem/1.3.0-rc1/golem.schema.json
3+
# Schema for vscode-yaml
4+
# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.3.0-rc1/golem.schema.json
5+
6+
# See https://learn.golem.cloud/docs/app-manifest#field-reference for field reference
7+
# For creating APIs see https://learn.golem.cloud/invoke/making-custom-apis
8+
9+
templates:
10+
ts:
11+
build:
12+
- command: npx tsc --noEmit false --emitDeclarationOnly --declaration --outFile ../../golem-temp/ts-check/{{ component_name | to_kebab_case }}/main.d.ts
13+
sources:
14+
- src
15+
- ../../common-ts
16+
- tsconfig.js
17+
targets:
18+
- ../../golem-temp/ts-check/{{ component_name | to_kebab_case }}/main.d.ts
19+
- command: npx --no golem-typegen ../../../components-ts/{{ component_name | to_kebab_case }}/tsconfig.json --files ../../../components-ts/{{ component_name | to_kebab_case }}/src/**/*.ts
20+
dir: ../../golem-temp/ts-metadata/{{ component_name | to_kebab_case }}
21+
sources:
22+
- ../../../components-ts/{{ component_name | to_kebab_case }}/src
23+
targets:
24+
- .metadata
25+
- command: npx --no rollup -- -c
26+
sources:
27+
- src
28+
- ../../common-ts
29+
- rollup.config.mjs
30+
- tsconfig.js
31+
- ../../golem-temp/ts-metadata/{{ component_name | to_kebab_case }}
32+
targets:
33+
- ../../golem-temp/ts-dist/{{ component_name | to_kebab_case }}/main.js
34+
- injectToPrebuiltQuickjs: ../../node_modules/@golemcloud/golem-ts-sdk/wasm/agent_guest.wasm
35+
module: ../../golem-temp/ts-dist/{{ component_name | to_kebab_case }}/main.js
36+
moduleWasm: ../../golem-temp/agents/{{ component_name | to_snake_case }}.module.wasm
37+
into: ../../golem-temp/agents/{{ component_name | to_snake_case }}.dynamic.wasm
38+
- generateAgentWrapper: ../../golem-temp/agents/{{ component_name | to_snake_case }}.wrapper.wasm
39+
basedOnCompiledWasm: ../../golem-temp/agents/{{ component_name | to_snake_case }}.dynamic.wasm
40+
- composeAgentWrapper: ../../golem-temp/agents/{{ component_name | to_snake_case }}.wrapper.wasm
41+
withAgent: ../../golem-temp/agents/{{ component_name | to_snake_case }}.dynamic.wasm
42+
to: ../../golem-temp/agents/{{ component_name | to_snake_case }}.static.wasm
43+
sourceWit: ../../node_modules/@golemcloud/golem-ts-sdk/wasm/agent_guest.wasm
44+
generatedWit: ../../golem-temp/agents/{{ component_name | to_snake_case }}/wit-generated
45+
componentWasm: ../../golem-temp/agents/{{ component_name | to_snake_case }}.static.wasm
46+
linkedWasm: ../../golem-temp/agents/{{ component_name | to_snake_case }}.wasm
47+
customCommands:
48+
copy:
49+
- command: cp ../../golem-temp/agents/{{ component_name | to_snake_case }}.wasm ../../../{{ component_name | to_snake_case }}.wasm
50+
customCommands:
51+
ts-npm-install:
52+
- command: npm install
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import alias from "@rollup/plugin-alias";
2+
import commonjs from "@rollup/plugin-commonjs";
3+
import json from "@rollup/plugin-json";
4+
import nodeResolve from "@rollup/plugin-node-resolve";
5+
import typescript from "@rollup/plugin-typescript";
6+
import url from "node:url";
7+
import path from "node:path";
8+
9+
export default function componentRollupConfig(componentName) {
10+
const dir = path.dirname(url.fileURLToPath(import.meta.url));
11+
12+
const externalPackages = (id) => {
13+
return (
14+
id === "@golemcloud/golem-ts-sdk" ||
15+
id.startsWith("golem:")
16+
);
17+
};
18+
19+
const virtualAgentMainId = "virtual:agent-main";
20+
const resolvedVirtualAgentMainId = "\0virtual:agent-main";
21+
22+
const virtualAgentMainPlugin = () => {
23+
return {
24+
name: "agent-main",
25+
resolveId(id) {
26+
if (id === virtualAgentMainId) {
27+
return resolvedVirtualAgentMainId;
28+
}
29+
},
30+
load(id) {
31+
if (id === resolvedVirtualAgentMainId) {
32+
return `
33+
import { TypescriptTypeRegistry } from '@golemcloud/golem-ts-sdk';
34+
import { Metadata } from '../../golem-temp/ts-metadata/${componentName}/.metadata/generated-types';
35+
36+
TypescriptTypeRegistry.register(Metadata);
37+
38+
// Using an async function to prevent rollup from reordering registration and main import.
39+
export default (async () => { return await import("./src/main");})();
40+
`
41+
}
42+
}
43+
};
44+
}
45+
46+
return {
47+
input: virtualAgentMainId,
48+
output: {
49+
file: `../../golem-temp/ts-dist/${componentName}/main.js`,
50+
format: "esm",
51+
inlineDynamicImports: true,
52+
sourcemap: false,
53+
},
54+
external: externalPackages,
55+
plugins: [
56+
virtualAgentMainPlugin(),
57+
alias({
58+
entries: [
59+
{
60+
find: "common",
61+
replacement: path.resolve(dir, "../common-ts/src"),
62+
},
63+
],
64+
}),
65+
nodeResolve({
66+
extensions: [".mjs", ".js", ".node", ".ts"],
67+
}),
68+
commonjs({
69+
include: ["../../node_modules/**"],
70+
}),
71+
json(),
72+
typescript({
73+
noEmitOnError: true,
74+
include: [
75+
"./src/**/*.ts",
76+
".agent/**/*.ts",
77+
".metadata/**/*.ts",
78+
"../../common-ts/src/**/*.ts",
79+
],
80+
}),
81+
],
82+
};
83+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function exampleCommonFunction() {
2+
return "hello common";
3+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"$schema": "https://json.schemastore.org/tsconfig",
3+
"compilerOptions": {
4+
"skipLibCheck": true,
5+
"target": "ES2020",
6+
"noEmit": true,
7+
"lib": ["ES2020"],
8+
"types": ["node"],
9+
"moduleResolution": "bundler",
10+
"checkJs": false,
11+
"strict": true,
12+
"noUncheckedIndexedAccess": true,
13+
"noImplicitOverride": true,
14+
"resolveJsonModule": true,
15+
"esModuleInterop": true,
16+
"experimentalDecorators": true,
17+
"emitDecoratorMetadata": true,
18+
"useDefineForClassFields": false,
19+
"paths": {
20+
"common/*": ["../common-ts/src/*"]
21+
}
22+
}
23+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/*/dist
2+
/*/src/generated
3+
/*/wit-generated
4+
/*/.metadata

0 commit comments

Comments
 (0)