Skip to content

Commit d10c567

Browse files
chore: separate explorer from gatekeeper (#1209)
* chore: separate explorer from gatekeeper * test: fix index export lint issues * test: restore sync coverage * chore: update generated OpenAPI docs * test: restore search db coverage * test: exclude test helpers from coverage * test: exclude gatekeeper production db adapters from coverage * ci: align docker test container uid * chore: standardize search server env vars * chore: silence dotenv info output * chore: order receipt pages by columns * fix: use signature time first * fix: mongo check indexes on start * fix: return after error status * fix mongo index startup migration * fix mongo replica set healthcheck * harden redis startup and logging --------- Co-authored-by: GitHub Action <action@github.com>
1 parent d8c56df commit d10c567

55 files changed

Lines changed: 8542 additions & 1522 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/docker-build-test.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
- name: Grab logs
5050
if: always()
5151
run: |
52-
docker compose logs --no-color keymaster cli gatekeeper redis > docker-compose-logs.txt
52+
docker compose logs --no-color keymaster cli gatekeeper redis search-server > docker-compose-logs.txt
5353
cat docker-compose-logs.txt
5454
5555

@@ -73,4 +73,3 @@ jobs:
7373
name: E2E Artifacts
7474
path: tests/test-results/cli-tests.xml
7575

76-

doc/gatekeeper-api.json

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,148 @@
978978
}
979979
}
980980
},
981+
"/index/export": {
982+
"post": {
983+
"summary": "Export a paginated DID index snapshot or incremental change batch.",
984+
"requestBody": {
985+
"required": true,
986+
"content": {
987+
"application/json": {
988+
"schema": {
989+
"type": "object",
990+
"required": [
991+
"mode"
992+
],
993+
"properties": {
994+
"mode": {
995+
"type": "string",
996+
"enum": [
997+
"snapshot",
998+
"changes"
999+
]
1000+
},
1001+
"cursor": {
1002+
"type": "string",
1003+
"nullable": true,
1004+
"description": "Opaque snapshot cursor or incremental change cursor."
1005+
},
1006+
"checkpointCursor": {
1007+
"type": "string",
1008+
"nullable": true,
1009+
"description": "Snapshot-only high-water change cursor returned by the first snapshot page and required on continuation pages."
1010+
},
1011+
"limit": {
1012+
"type": "integer",
1013+
"minimum": 1
1014+
}
1015+
}
1016+
}
1017+
}
1018+
}
1019+
},
1020+
"responses": {
1021+
"200": {
1022+
"description": "Index export page.",
1023+
"content": {
1024+
"application/json": {
1025+
"schema": {
1026+
"oneOf": [
1027+
{
1028+
"type": "object",
1029+
"required": [
1030+
"mode",
1031+
"cursor",
1032+
"checkpointCursor",
1033+
"hasMore",
1034+
"dids",
1035+
"blocks"
1036+
],
1037+
"properties": {
1038+
"mode": {
1039+
"type": "string",
1040+
"enum": [
1041+
"snapshot"
1042+
]
1043+
},
1044+
"cursor": {
1045+
"type": "string",
1046+
"nullable": true,
1047+
"description": "Opaque snapshot page cursor. Clients must store and pass it back without interpretation."
1048+
},
1049+
"checkpointCursor": {
1050+
"type": "string",
1051+
"nullable": true,
1052+
"description": "Snapshot high-water change cursor returned on every snapshot page."
1053+
},
1054+
"hasMore": {
1055+
"type": "boolean"
1056+
},
1057+
"dids": {
1058+
"type": "array",
1059+
"items": {
1060+
"type": "object"
1061+
}
1062+
},
1063+
"blocks": {
1064+
"type": "array",
1065+
"items": {
1066+
"type": "object"
1067+
}
1068+
}
1069+
}
1070+
},
1071+
{
1072+
"type": "object",
1073+
"required": [
1074+
"mode",
1075+
"cursor",
1076+
"hasMore",
1077+
"dids",
1078+
"blocks"
1079+
],
1080+
"properties": {
1081+
"mode": {
1082+
"type": "string",
1083+
"enum": [
1084+
"changes"
1085+
]
1086+
},
1087+
"cursor": {
1088+
"type": "string",
1089+
"nullable": true,
1090+
"description": "Incremental change cursor."
1091+
},
1092+
"hasMore": {
1093+
"type": "boolean"
1094+
},
1095+
"dids": {
1096+
"type": "array",
1097+
"items": {
1098+
"type": "object"
1099+
}
1100+
},
1101+
"blocks": {
1102+
"type": "array",
1103+
"items": {
1104+
"type": "object"
1105+
}
1106+
}
1107+
}
1108+
}
1109+
]
1110+
}
1111+
}
1112+
}
1113+
},
1114+
"400": {
1115+
"description": "Invalid request body."
1116+
},
1117+
"500": {
1118+
"description": "Internal Server Error."
1119+
}
1120+
}
1121+
}
1122+
},
9811123
"/dids/remove": {
9821124
"post": {
9831125
"summary": "Remove one or more DIDs",

docker-compose.yml

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
services:
22
mongodb:
33
image: mongo:8.0
4+
command: [ "mongod", "--replSet", "rs0", "--bind_ip_all" ]
45
volumes:
56
- ./data/mongodb:/data/db
67
ports:
78
- 127.0.0.1:27017:27017
9+
healthcheck:
10+
test: [ "CMD-SHELL", "mongosh --quiet --eval \"const host = 'mongodb:27017'; try { const cfg = rs.conf(); if (cfg._id !== 'rs0' || cfg.members.length !== 1 || cfg.members[0].host !== host) { cfg._id = 'rs0'; cfg.version = (cfg.version || 1) + 1; cfg.members = [{ _id: 0, host }]; rs.reconfig(cfg, { force: true }); } } catch (err) { try { rs.initiate({ _id: 'rs0', members: [{ _id: 0, host }] }); } catch (initErr) {} } try { quit(db.adminCommand({ hello: 1 }).isWritablePrimary ? 0 : 1); } catch (err) { quit(1); }\"" ]
11+
interval: 5s
12+
timeout: 5s
13+
retries: 30
14+
start_period: 5s
815

916
redis:
1017
image: redis:8.0.4-alpine
@@ -14,6 +21,12 @@ services:
1421
- ./data/redis:/data
1522
ports:
1623
- 127.0.0.1:6379:6379
24+
healthcheck:
25+
test: [ "CMD", "redis-cli", "ping" ]
26+
interval: 5s
27+
timeout: 5s
28+
retries: 10
29+
start_period: 5s
1730

1831
postgres:
1932
image: postgres:17-alpine
@@ -65,7 +78,7 @@ services:
6578
- KC_GATEKEEPER_RATE_LIMIT_WHITELIST=${KC_GATEKEEPER_RATE_LIMIT_WHITELIST}
6679
- KC_GATEKEEPER_RATE_LIMIT_SKIP_PATHS=${KC_GATEKEEPER_RATE_LIMIT_SKIP_PATHS}
6780
- KC_LOG_LEVEL=${KC_LOG_LEVEL}
68-
- KC_MONGODB_URL=mongodb://mongodb:27017
81+
- KC_MONGODB_URL=mongodb://mongodb:27017/?replicaSet=rs0
6982
- KC_REDIS_URL=redis://redis:6379
7083
- KC_POSTGRES_URL=postgresql://${KC_POSTGRES_USER:-mdip}:${KC_POSTGRES_PASSWORD:-mdip}@postgres:5432/${KC_POSTGRES_DB:-mdip}
7184
- KC_IPFS_ENABLE=${KC_IPFS_ENABLE}
@@ -78,9 +91,12 @@ services:
7891
ports:
7992
- ${KC_GATEKEEPER_PORT}:4224
8093
depends_on:
81-
- mongodb
82-
- redis
83-
- postgres
94+
mongodb:
95+
condition: service_healthy
96+
redis:
97+
condition: service_healthy
98+
postgres:
99+
condition: service_started
84100

85101
keymaster:
86102
build:
@@ -91,7 +107,7 @@ services:
91107
- KC_KEYMASTER_PORT=4226
92108
- KC_GATEKEEPER_URL=http://gatekeeper:4224
93109
- KC_DISABLE_SEARCH=${KC_DISABLE_SEARCH:-false}
94-
- KC_SEARCH_URL=http://search-server:${SEARCH_SERVER_PORT:-4002}
110+
- KC_SEARCH_URL=http://search-server:${KC_SEARCH_SERVER_PORT:-4002}
95111
- KC_NODE_ID=${KC_NODE_ID}
96112
- KC_KEYMASTER_DB=${KC_KEYMASTER_DB}
97113
- KC_ENCRYPTED_PASSPHRASE=${KC_ENCRYPTED_PASSPHRASE}
@@ -106,7 +122,7 @@ services:
106122
- KC_KEYMASTER_RATE_LIMIT_WHITELIST=${KC_KEYMASTER_RATE_LIMIT_WHITELIST}
107123
- KC_KEYMASTER_RATE_LIMIT_SKIP_PATHS=${KC_KEYMASTER_RATE_LIMIT_SKIP_PATHS}
108124
- KC_LOG_LEVEL=${KC_LOG_LEVEL}
109-
- KC_MONGODB_URL=mongodb://mongodb:27017
125+
- KC_MONGODB_URL=mongodb://mongodb:27017/?replicaSet=rs0
110126
- KC_REDIS_URL=redis://redis:6379
111127
- KC_POSTGRES_URL=postgresql://${KC_POSTGRES_USER:-mdip}:${KC_POSTGRES_PASSWORD:-mdip}@postgres:5432/${KC_POSTGRES_DB:-mdip}
112128
volumes:
@@ -115,11 +131,16 @@ services:
115131
ports:
116132
- ${KC_KEYMASTER_PORT}:4226
117133
depends_on:
118-
- gatekeeper
119-
- redis
120-
- mongodb
121-
- postgres
122-
- search-server
134+
gatekeeper:
135+
condition: service_started
136+
redis:
137+
condition: service_healthy
138+
mongodb:
139+
condition: service_healthy
140+
postgres:
141+
condition: service_started
142+
search-server:
143+
condition: service_started
123144

124145
hypr-mediator:
125146
build:
@@ -164,7 +185,7 @@ services:
164185
environment:
165186
- KC_GATEKEEPER_URL=http://gatekeeper:4224
166187
- KC_KEYMASTER_URL=http://keymaster:4226
167-
- KC_MONGODB_URL=mongodb://mongodb:27017
188+
- KC_MONGODB_URL=mongodb://mongodb:27017/?replicaSet=rs0
168189
- KC_REDIS_URL=redis://redis:6379
169190
- KC_POSTGRES_URL=postgresql://${KC_POSTGRES_USER:-mdip}:${KC_POSTGRES_PASSWORD:-mdip}@postgres:5432/${KC_POSTGRES_DB:-mdip}
170191
- KC_NODE_ID=${KC_NODE_ID}
@@ -208,7 +229,7 @@ services:
208229
environment:
209230
- KC_GATEKEEPER_URL=http://gatekeeper:4224
210231
- KC_KEYMASTER_URL=http://keymaster:4226
211-
- KC_MONGODB_URL=mongodb://mongodb:27017
232+
- KC_MONGODB_URL=mongodb://mongodb:27017/?replicaSet=rs0
212233
- KC_REDIS_URL=redis://redis:6379
213234
- KC_POSTGRES_URL=postgresql://${KC_POSTGRES_USER:-mdip}:${KC_POSTGRES_PASSWORD:-mdip}@postgres:5432/${KC_POSTGRES_DB:-mdip}
214235
- KC_NODE_ID=${KC_NODE_ID}
@@ -250,7 +271,7 @@ services:
250271
environment:
251272
- KC_GATEKEEPER_URL=http://gatekeeper:4224
252273
- KC_KEYMASTER_URL=http://keymaster:4226
253-
- KC_MONGODB_URL=mongodb://mongodb:27017
274+
- KC_MONGODB_URL=mongodb://mongodb:27017/?replicaSet=rs0
254275
- KC_REDIS_URL=redis://redis:6379
255276
- KC_POSTGRES_URL=postgresql://${KC_POSTGRES_USER:-mdip}:${KC_POSTGRES_PASSWORD:-mdip}@postgres:5432/${KC_POSTGRES_DB:-mdip}
256277
- KC_NODE_ID=${KC_NODE_ID}
@@ -294,7 +315,7 @@ services:
294315
environment:
295316
- KC_GATEKEEPER_URL=http://gatekeeper:4224
296317
- KC_KEYMASTER_URL=http://keymaster:4226
297-
- KC_MONGODB_URL=mongodb://mongodb:27017
318+
- KC_MONGODB_URL=mongodb://mongodb:27017/?replicaSet=rs0
298319
- KC_REDIS_URL=redis://redis:6379
299320
- KC_POSTGRES_URL=postgresql://${KC_POSTGRES_USER:-mdip}:${KC_POSTGRES_PASSWORD:-mdip}@postgres:5432/${KC_POSTGRES_DB:-mdip}
300321
- KC_NODE_ID=${KC_NODE_ID}
@@ -331,7 +352,7 @@ services:
331352
environment:
332353
- KC_GATEKEEPER_URL=http://gatekeeper:4224
333354
- KC_KEYMASTER_URL=http://keymaster:4226
334-
- KC_MONGODB_URL=mongodb://mongodb:27017
355+
- KC_MONGODB_URL=mongodb://mongodb:27017/?replicaSet=rs0
335356
- KC_REDIS_URL=redis://redis:6379
336357
- KC_POSTGRES_URL=postgresql://${KC_POSTGRES_USER:-mdip}:${KC_POSTGRES_PASSWORD:-mdip}@postgres:5432/${KC_POSTGRES_DB:-mdip}
337358
- KC_NODE_ID=${KC_NODE_ID}
@@ -384,39 +405,39 @@ services:
384405
image: keychainmdip/explorer
385406
environment:
386407
- VITE_EXPLORER_PORT=4000
387-
- VITE_GATEKEEPER_URL=http://localhost:4224
388-
- VITE_SEARCH_SERVER=http://localhost:${SEARCH_SERVER_PORT:-4002}
408+
- VITE_SEARCH_SERVER=http://localhost:${KC_SEARCH_SERVER_PORT:-4002}
389409
- VITE_OPERATION_NETWORKS=hyperswarm,local,TFTC,TBTC
390410
- KC_LOG_LEVEL=${KC_LOG_LEVEL}
391411
ports:
392412
- "4000:4000"
393413
depends_on:
394-
- gatekeeper
414+
- search-server
395415

396416
search-server:
397417
build:
398418
context: .
399419
dockerfile: Dockerfile.search-server
400420
image: keychainmdip/search-server
401421
environment:
402-
- SEARCH_SERVER_PORT=${SEARCH_SERVER_PORT:-4002}
403-
- SEARCH_SERVER_GATEKEEPER_URL=${SEARCH_SERVER_GATEKEEPER_URL:-http://gatekeeper:4224}
404-
- SEARCH_SERVER_REFRESH_INTERVAL_MS=${SEARCH_SERVER_REFRESH_INTERVAL_MS:-5000}
405-
- SEARCH_SERVER_DB=${KC_SEARCH_SERVER_DB:-sqlite}
406-
- SEARCH_SERVER_POSTGRES_URL=postgresql://${KC_POSTGRES_USER:-mdip}:${KC_POSTGRES_PASSWORD:-mdip}@postgres:5432/${KC_POSTGRES_DB:-mdip}
407-
- SEARCH_SERVER_TRUST_PROXY=${SEARCH_SERVER_TRUST_PROXY:-false}
408-
- SEARCH_SERVER_RATE_LIMIT_ENABLED=${SEARCH_SERVER_RATE_LIMIT_ENABLED:-false}
409-
- SEARCH_SERVER_RATE_LIMIT_WINDOW_VALUE=${SEARCH_SERVER_RATE_LIMIT_WINDOW_VALUE:-1}
410-
- SEARCH_SERVER_RATE_LIMIT_WINDOW_UNIT=${SEARCH_SERVER_RATE_LIMIT_WINDOW_UNIT:-minute}
411-
- SEARCH_SERVER_RATE_LIMIT_MAX_REQUESTS=${SEARCH_SERVER_RATE_LIMIT_MAX_REQUESTS:-600}
412-
- SEARCH_SERVER_RATE_LIMIT_WHITELIST=${SEARCH_SERVER_RATE_LIMIT_WHITELIST:-}
413-
- SEARCH_SERVER_RATE_LIMIT_SKIP_PATHS=${SEARCH_SERVER_RATE_LIMIT_SKIP_PATHS:-/api/v1/ready}
422+
- KC_SEARCH_SERVER_PORT=${KC_SEARCH_SERVER_PORT:-4002}
423+
- KC_SEARCH_SERVER_GATEKEEPER_URL=${KC_SEARCH_SERVER_GATEKEEPER_URL:-http://gatekeeper:4224}
424+
- KC_SEARCH_SERVER_REFRESH_INTERVAL_MS=${KC_SEARCH_SERVER_REFRESH_INTERVAL_MS:-5000}
425+
- KC_SEARCH_SERVER_DB=${KC_SEARCH_SERVER_DB:-sqlite}
426+
- KC_SEARCH_SERVER_POSTGRES_URL=${KC_SEARCH_SERVER_POSTGRES_URL:-}
427+
- KC_POSTGRES_URL=postgresql://${KC_POSTGRES_USER:-mdip}:${KC_POSTGRES_PASSWORD:-mdip}@postgres:5432/${KC_POSTGRES_DB:-mdip}
428+
- KC_SEARCH_SERVER_TRUST_PROXY=${KC_SEARCH_SERVER_TRUST_PROXY:-false}
429+
- KC_SEARCH_SERVER_RATE_LIMIT_ENABLED=${KC_SEARCH_SERVER_RATE_LIMIT_ENABLED:-false}
430+
- KC_SEARCH_SERVER_RATE_LIMIT_WINDOW_VALUE=${KC_SEARCH_SERVER_RATE_LIMIT_WINDOW_VALUE:-1}
431+
- KC_SEARCH_SERVER_RATE_LIMIT_WINDOW_UNIT=${KC_SEARCH_SERVER_RATE_LIMIT_WINDOW_UNIT:-minute}
432+
- KC_SEARCH_SERVER_RATE_LIMIT_MAX_REQUESTS=${KC_SEARCH_SERVER_RATE_LIMIT_MAX_REQUESTS:-600}
433+
- KC_SEARCH_SERVER_RATE_LIMIT_WHITELIST=${KC_SEARCH_SERVER_RATE_LIMIT_WHITELIST:-}
434+
- KC_SEARCH_SERVER_RATE_LIMIT_SKIP_PATHS=${KC_SEARCH_SERVER_RATE_LIMIT_SKIP_PATHS:-/api/v1/ready,/api/v1/status}
414435
- KC_LOG_LEVEL=${KC_LOG_LEVEL}
415436
volumes:
416437
- ./data:/app/search-server/data
417438
user: "${KC_UID}:${KC_GID}"
418439
ports:
419-
- "${SEARCH_SERVER_PORT:-4002}:${SEARCH_SERVER_PORT:-4002}"
440+
- "${KC_SEARCH_SERVER_PORT:-4002}:${KC_SEARCH_SERVER_PORT:-4002}"
420441
depends_on:
421442
- gatekeeper
422443

@@ -429,7 +450,7 @@ services:
429450
- VITE_PORT=${KC_REACT_WALLET_PORT:-4228}
430451
- VITE_GATEKEEPER_URL=http://gatekeeper:4224
431452
- VITE_KEYMASTER_URL=http://keymaster:4226
432-
- VITE_SEARCH_SERVER=http://search-server:${SEARCH_SERVER_PORT:-4002}
453+
- VITE_SEARCH_SERVER=http://search-server:${KC_SEARCH_SERVER_PORT:-4002}
433454
user: "${KC_UID}:${KC_GID}"
434455
ports:
435456
- "${KC_REACT_WALLET_PORT:-4228}:${KC_REACT_WALLET_PORT:-4228}"

jest.config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ const config = {
3737
'^\\.\\/sync-persistence\\.js$': '<rootDir>/services/mediators/hyperswarm/src/sync-persistence.ts',
3838
'^\\.\\/windows\\.js$': '<rootDir>/services/mediators/hyperswarm/src/negentropy/windows.ts',
3939
'^\\.\\/abstract-json\\.js$': '<rootDir>/packages/gatekeeper/src/db/abstract-json.ts',
40+
'^\\.\\/db-utils\\.js$': '<rootDir>/services/search-server/src/db/db-utils.ts',
41+
'^\\.\\/did-resolver\\.js$': '<rootDir>/packages/gatekeeper/src/did-resolver.ts',
42+
'^\\.\\/index-export\\.js$': '<rootDir>/packages/gatekeeper/src/db/index-export.ts',
43+
'^\\.\\/index-helpers\\.js$': '<rootDir>/services/search-server/src/index-helpers.ts',
44+
'^\\.\\/projections\\.js$': '<rootDir>/services/search-server/src/projections.ts',
4045
'^\\.\\/published-credentials\\.js$': '<rootDir>/services/search-server/src/published-credentials.ts',
4146
'^\\.\\/challenge-receipts\\.js$': '<rootDir>/services/search-server/src/challenge-receipts.ts',
4247
'^\\.\\/cipher-base\\.js$': '<rootDir>/packages/cipher/src/cipher-base.ts',
@@ -49,6 +54,11 @@ const config = {
4954
],
5055
coveragePathIgnorePatterns: [
5156
"/node_modules/",
57+
"/tests/",
58+
"/packages/gatekeeper/src/db/mongo\\.ts$",
59+
"/packages/gatekeeper/src/db/postgres\\.ts$",
60+
"/packages/gatekeeper/src/db/redis\\.ts$",
61+
"/packages/gatekeeper/src/db/sqlite\\.ts$",
5262
"/services/mediators/hyperswarm/src/negentropy/Negentropy\\.cjs$",
5363
]
5464
};

0 commit comments

Comments
 (0)