Skip to content

Commit 0d532c5

Browse files
authored
Merge pull request elizaOS#1470 from CliqueOfficial/feat/tee
feat: support TEE logging and support running eliza in Intel SGX
2 parents b5e1c9d + 22bc36f commit 0d532c5

35 files changed

+1428
-0
lines changed

.env.example

+2
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ ZEROG_FLOW_ADDRESS=
340340
TEE_MODE=OFF # LOCAL | DOCKER | PRODUCTION
341341
WALLET_SECRET_SALT= # ONLY define if you want to use TEE Plugin, otherwise it will throw errors
342342

343+
ENABLE_TEE_LOG=false # Set to true to enable TEE logging, only available when running eliza in TEE
344+
343345
# Flow Blockchain Configuration
344346
FLOW_ADDRESS=
345347
FLOW_PRIVATE_KEY= # Private key for SHA3-256 + P256 ECDSA

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,7 @@ coverage
5757
.eslintcache
5858

5959
agent/content
60+
61+
eliza.manifest
62+
eliza.manifest.sgx
63+
eliza.sig

Makefile

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Copyright (C) 2024 Gramine contributors
2+
# SPDX-License-Identifier: BSD-3-Clause
3+
4+
THIS_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
5+
NODEJS_DIR ?= /usr/bin
6+
7+
ARCH_LIBDIR ?= /lib/$(shell $(CC) -dumpmachine)
8+
9+
ifeq ($(DEBUG),1)
10+
GRAMINE_LOG_LEVEL = debug
11+
else
12+
GRAMINE_LOG_LEVEL = error
13+
endif
14+
15+
.PHONY: all
16+
all: eliza.manifest
17+
ifeq ($(SGX),1)
18+
all: eliza.manifest.sgx eliza.sig
19+
endif
20+
21+
.PHONY: eliza.manifest
22+
eliza.manifest: eliza.manifest.template
23+
gramine-manifest \
24+
-Dlog_level=$(GRAMINE_LOG_LEVEL) \
25+
-Darch_libdir=$(ARCH_LIBDIR) \
26+
-Dnodejs_dir=$(NODEJS_DIR) \
27+
$< >$@
28+
29+
# Make on Ubuntu <= 20.04 doesn't support "Rules with Grouped Targets" (`&:`),
30+
# for details on this workaround see
31+
# https://github.com/gramineproject/gramine/blob/e8735ea06c/CI-Examples/helloworld/Makefile
32+
eliza.manifest.sgx eliza.sig: sgx_sign
33+
@:
34+
35+
.INTERMEDIATE: sgx_sign
36+
sgx_sign: eliza.manifest
37+
gramine-sgx-sign \
38+
--manifest $< \
39+
--output $<.sgx
40+
41+
ifeq ($(SGX),)
42+
GRAMINE = gramine-direct
43+
else
44+
GRAMINE = gramine-sgx
45+
endif
46+
47+
# Start the default character:
48+
# SGX=1 make start
49+
# Start a specific character by passing arguments:
50+
# SGX=1 make start -- --character "character/your_character_file.json"
51+
.PHONY: start
52+
start: all
53+
$(GRAMINE) ./eliza --loader ts-node/esm src/index.ts --isRoot $(filter-out $@,$(MAKECMDGOALS))
54+
.PHONY: clean
55+
clean:
56+
$(RM) *.manifest *.manifest.sgx *.sig
57+
58+
.PHONY: distclean
59+
distclean: clean

agent/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@
6262
"@elizaos/plugin-giphy": "workspace:*",
6363
"@elizaos/plugin-ton": "workspace:*",
6464
"@elizaos/plugin-sui": "workspace:*",
65+
"@elizaos/plugin-sgx": "workspace:*",
6566
"@elizaos/plugin-tee": "workspace:*",
67+
"@elizaos/plugin-tee-log": "workspace:*",
6668
"@elizaos/plugin-tee-marlin": "workspace:*",
6769
"@elizaos/plugin-multiversx": "workspace:*",
6870
"@elizaos/plugin-near": "workspace:*",

agent/src/index.ts

+8
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ import { solanaPlugin } from "@elizaos/plugin-solana";
7070
import { solanaAgentkitPlguin } from "@elizaos/plugin-solana-agentkit";
7171
import { storyPlugin } from "@elizaos/plugin-story";
7272
import { suiPlugin } from "@elizaos/plugin-sui";
73+
import { sgxPlugin } from "@elizaos/plugin-sgx";
7374
import { TEEMode, teePlugin } from "@elizaos/plugin-tee";
75+
import { teeLogPlugin } from "@elizaos/plugin-tee-log";
7476
import { teeMarlinPlugin } from "@elizaos/plugin-tee-marlin";
7577
import { tonPlugin } from "@elizaos/plugin-ton";
7678
import { webSearchPlugin } from "@elizaos/plugin-web-search";
@@ -664,6 +666,12 @@ export async function createAgent(
664666
]
665667
: []),
666668
...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),
669+
getSecret(character, "SGX") ? sgxPlugin : null,
670+
(getSecret(character, "ENABLE_TEE_LOG") &&
671+
((teeMode !== TEEMode.OFF && walletSecretSalt) ||
672+
getSecret(character, "SGX")))
673+
? teeLogPlugin
674+
: null,
667675
getSecret(character, "COINBASE_API_KEY") &&
668676
getSecret(character, "COINBASE_PRIVATE_KEY") &&
669677
getSecret(character, "COINBASE_NOTIFICATION_URI")

eliza.manifest.template

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Copyright (C) 2024 Gramine contributors
2+
# SPDX-License-Identifier: BSD-3-Clause
3+
4+
# Node.js manifest file example
5+
6+
libos.entrypoint = "{{ nodejs_dir }}/node"
7+
8+
fs.start_dir = "/agent"
9+
10+
loader.log_level = "{{ log_level }}"
11+
12+
loader.env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr/{{ arch_libdir }}"
13+
14+
# Insecure configuration for loading arguments and environment variables
15+
# Do not set these configurations in production
16+
loader.insecure__use_cmdline_argv = true
17+
loader.insecure__use_host_env = true
18+
19+
fs.mounts = [
20+
{ uri = "file:{{ gramine.runtimedir() }}", path = "/lib" },
21+
{ uri = "file:{{ arch_libdir }}", path = "{{ arch_libdir }}" },
22+
{ uri = "file:/usr/{{ arch_libdir }}", path = "/usr/{{ arch_libdir }}" },
23+
{ uri = "file:{{ nodejs_dir }}/node", path = "{{ nodejs_dir }}/node" },
24+
{ type = "tmpfs", path = "/tmp" },
25+
{ type = "tmpfs", path = "/agent/content_cache" },
26+
]
27+
28+
sys.enable_extra_runtime_domain_names_conf = true
29+
sys.fds.limit = 65535
30+
31+
sgx.debug = false
32+
sgx.remote_attestation = "dcap"
33+
sgx.max_threads = 64
34+
35+
# Some dependencies of Eliza utilize WebAssembly (WASM).
36+
# Initializing WASM requires a substantial amount of memory.
37+
# If there is insufficient memory, you may encounter the following error:
38+
# RangeError: WebAssembly.instantiate(): Out of memory: Cannot allocate Wasm memory for a new instance.
39+
# To address this, we set the enclave size to 64GB.
40+
sgx.enclave_size = "64G"
41+
42+
# `use_exinfo = true` is needed because Node.js uses memory mappings with `MAP_NORESERVE`, which
43+
# will defer page accepts to page-fault events when EDMM is enabled
44+
sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }}
45+
sgx.use_exinfo = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }}
46+
47+
sgx.trusted_files = [
48+
"file:{{ gramine.runtimedir() }}/",
49+
"file:{{ arch_libdir }}/",
50+
"file:/usr/{{ arch_libdir }}/",
51+
"file:{{ nodejs_dir }}/node",
52+
"file:characters/",
53+
"file:agent/src/",
54+
"file:agent/package.json",
55+
"file:agent/tsconfig.json",
56+
"file:package.json",
57+
"file:.env",
58+
59+
# Add these files to sgx.trusted_files in production and remove them from sgx.allowed_files.
60+
# Trusting these files requires a high-performance SGX machine due to the large number of files,
61+
# which could significantly increase startup time.
62+
# To mitigate startup time degradation, we use allowed_files in development.
63+
#
64+
# "file:node_modules/",
65+
# "file:packages/",
66+
# These files are symbolic links to node_modules,
67+
# and Gramine does not support adding symbolic link directories to sgx.trusted_files.
68+
# Therefore, we must add each directory individually to sgx.trusted_files.
69+
# "file:agent/node_modules/@elizaos/adapter-sqlite/",
70+
# "file:agent/node_modules/@elizaos/.../",
71+
]
72+
73+
# Insecure configuration. Use gramine encrypted fs to store data in production.
74+
sgx.allowed_files = [
75+
"file:agent/data/",
76+
"file:agent/model.gguf",
77+
78+
# Move these files to sgx.trusted_files in production.
79+
"file:node_modules/",
80+
"file:packages/",
81+
"file:agent/node_modules/",
82+
]
83+
84+
loader.env.SGX = "1"

packages/client-direct/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"dependencies": {
2222
"@elizaos/core": "workspace:*",
2323
"@elizaos/plugin-image-generation": "workspace:*",
24+
"@elizaos/plugin-tee-log": "workspace:*",
2425
"@types/body-parser": "1.19.5",
2526
"@types/cors": "2.8.17",
2627
"@types/express": "5.0.0",

packages/client-direct/src/README.md

+145
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,148 @@ curl -X GET "http://localhost:3000/fine-tune/8566c47a-ada8-441c-95bc-7bb07656c4c
4343
-H "Content-Type: application/json" \
4444
-H "Authorization: Bearer jvBpxrTNqGqhnfQhSEqCdsG6aTSP8IBL".
4545
```
46+
47+
# TEE Logging
48+
49+
TEE Logging is a feature that allows you to log the activities of your agents. Through these logs, you can verify that the actions of the agents are protected by the TEE and that they are executed autonomously by Eliza, without any third-party interference.
50+
51+
## Setup
52+
53+
You need to setup the TEE log plugin first. Follow the [TEE Log Plugin](../plugin-tee-log/README.md) to setup the plugin.
54+
55+
## Get all TEE agents Information
56+
57+
```bash
58+
curl -X GET --location "http://localhost:3000/tee/agents"
59+
```
60+
61+
Example response when success:
62+
63+
```json
64+
{
65+
"agents": [
66+
{
67+
"id": "f18738bb-edab-45f6-805d-7f26dbfdba87",
68+
"agentId": "75490f32-c06a-0005-9804-339453d3fe2f",
69+
"agentName": "tea",
70+
"createdAt": 1735222963153,
71+
"publicKey": "02e1a9dde5462ee40bc2df7cc3f0dc88c6e582ea1c4ccf5a30e9dd7fbed736b0fe",
72+
"attestation": "{\"quote\":\"0x03000200000000000...d2d2d2d0a00\",\"timestamp\":1735222963152}"
73+
}
74+
],
75+
"attestation": "{\"quote\":\"0x0300020000000...4452d2d2d2d2d0a00\",\"timestamp\":1735223101255}"
76+
}
77+
```
78+
79+
Note that the user report included in the attestation contains the SHA256 hash of the value of the "agents" field. Specifically, it is calculated as follows: `SHA256(JSON.stringify(agents value))`. By verifying the attestation, you can retrieve this hash value and ensure the integrity of the agents' information.
80+
81+
82+
Example response when error:
83+
84+
```json
85+
{
86+
"error": "Failed to get TEE agents"
87+
}
88+
```
89+
90+
## Get TEE agent Information by agentId
91+
92+
```bash
93+
curl -X GET --location "http://localhost:3000/tee/agents/75490f32-c06a-0005-9804-339453d3fe2f"
94+
```
95+
96+
Example response when success:
97+
98+
```json
99+
{
100+
"agent": {
101+
"id": "f18738bb-edab-45f6-805d-7f26dbfdba87",
102+
"agentId": "75490f32-c06a-0005-9804-339453d3fe2f",
103+
"agentName": "tea",
104+
"createdAt": 1735222963153,
105+
"publicKey": "02e1a9dde5462ee40bc2df7cc3f0dc88c6e582ea1c4ccf5a30e9dd7fbed736b0fe",
106+
"attestation": "{\"quote\":\"0x0300020...452d2d2d2d2d0a00\",\"timestamp\":1735222963152}"
107+
},
108+
"attestation": "{\"quote\":\"0x03000200000000000...d2d2d2d2d0a00\",\"timestamp\":1735223294916}"
109+
}
110+
```
111+
112+
Note that the user report included in the attestation contains the SHA256 hash of the value of the "agent" field. Specifically, it is calculated as follows: `SHA256(JSON.stringify(agent value))`. By verifying the attestation, you can retrieve this hash value and ensure the integrity of the agent's information.
113+
114+
Example response when error:
115+
116+
```json
117+
{
118+
"error": "Failed to get TEE agent"
119+
}
120+
```
121+
122+
## Get TEE log
123+
124+
```bash
125+
curl -X POST --location "http://localhost:3000/tee/logs" \
126+
-H "Content-Type: application/json" \
127+
-d '{
128+
"query": {
129+
"agentId": "75490f32-c06a-0005-9804-339453d3fe2f"
130+
},
131+
"page": 1,
132+
"pageSize": 10
133+
}'
134+
```
135+
136+
There are optional parameters in the `query` parameter:
137+
138+
- **agentId**: (string, optional) The ID of the agent whose logs you want to retrieve.
139+
- **roomId**: (string, optional) The ID of the room associated with the logs.
140+
- **userId**: (string, optional) The ID of the user related to the logs.
141+
- **type**: (string, optional) The type of logs to filter.
142+
- **containsContent**: (string, optional) A substring to search for within the log content.
143+
- **startTimestamp**: (number, optional) The starting timestamp for filtering logs.
144+
- **endTimestamp**: (number, optional) The ending timestamp for filtering logs.
145+
146+
147+
Example response when success:
148+
149+
```json
150+
{
151+
"logs": {
152+
"page": 1,
153+
"pageSize": 10,
154+
"total": 2,
155+
"data": [
156+
{
157+
"id": "01aac44e-d482-42df-8acc-6e6bfbb798f0",
158+
"agentId": "75490f32-c06a-0005-9804-339453d3fe2f",
159+
"roomId": "322d5683-fe3c-056a-8f1a-6b002e0a5c22",
160+
"userId": "12dea96f-ec20-0935-a6ab-75692c994959",
161+
"type": "Action:CONTINUE",
162+
"content": "Continue",
163+
"timestamp": 1735222998263,
164+
"signature": "0x304402201a5bd4eb5807293ba0612b835eaaa56742c04603dbe08e3c7d247cdae3dc4b6f022034a165e1d63f1d58cb0976f615f6acd052f5e11154cef76d7c14c8ba99249833"
165+
},
166+
{
167+
"id": "6275e742-3ebf-477c-ab45-99d2c701c4b5",
168+
"agentId": "75490f32-c06a-0005-9804-339453d3fe2f",
169+
"roomId": "322d5683-fe3c-056a-8f1a-6b002e0a5c22",
170+
"userId": "12dea96f-ec20-0935-a6ab-75692c994959",
171+
"type": "Action:CONTINUE",
172+
"content": "Continue",
173+
"timestamp": 1735223036272,
174+
"signature": "0x304402201a5bd4eb5807293ba0612b835eaaa56742c04603dbe08e3c7d247cdae3dc4b6f022034a165e1d63f1d58cb0976f615f6acd052f5e11154cef76d7c14c8ba99249833"
175+
}
176+
]
177+
},
178+
"attestation": "{\"quote\":\"0x0300020000000000...4154452d2d2d2d2d0a00\",\"timestamp\":1735223364956}"
179+
}
180+
```
181+
182+
Note that the user report included in the attestation contains the SHA256 hash of the value of the "logs" field. Specifically, it is calculated as follows: `SHA256(JSON.stringify(logs value))`. By verifying the attestation, you can retrieve this hash value and ensure the integrity of the logs
183+
184+
Example response when error:
185+
186+
```json
187+
{
188+
"error": "Failed to get TEE logs"
189+
}
190+
```

0 commit comments

Comments
 (0)