mlgym-deploy 2.0.0
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/ADD_TO_CURSOR_SETTINGS.json +28 -0
- package/CURSOR_SETUP.md +119 -0
- package/README.md +43 -0
- package/claude-desktop-config.json +8 -0
- package/cursor-config.json +13 -0
- package/cursor-integration.js +165 -0
- package/cursor-prompt-config.json +27 -0
- package/deploy-hello-world.sh +103 -0
- package/index-v2.js +1040 -0
- package/index-v3-explicit.js +129 -0
- package/index.js +5238 -0
- package/package.json +45 -0
- package/tests/README.md +90 -0
- package/tests/mlgym_auth_login_test.sh +170 -0
- package/tests/mlgym_auth_logout_test.sh +157 -0
- package/tests/mlgym_deployments_test.sh +204 -0
- package/tests/mlgym_project_init_test.sh +148 -0
- package/tests/mlgym_projects_get_test.sh +159 -0
- package/tests/mlgym_projects_list_test.sh +162 -0
- package/tests/mlgym_user_create_test.sh +203 -0
- package/tests/run-all-tests.sh +63 -0
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mlgym-deploy",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "MCP server for GitLab Backend - User creation and project deployment",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mlgym-mcp": "./index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node index.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mcp",
|
|
15
|
+
"gitlab",
|
|
16
|
+
"coolify",
|
|
17
|
+
"deployment",
|
|
18
|
+
"model-context-protocol",
|
|
19
|
+
"mlgym"
|
|
20
|
+
],
|
|
21
|
+
"author": "MLGym Team",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git@code.stratus5.com:chka/gitlab_backend.git"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@modelcontextprotocol/sdk": "^0.6.0",
|
|
29
|
+
"axios": "^1.6.0"
|
|
30
|
+
},
|
|
31
|
+
"mcp": {
|
|
32
|
+
"name": "GitLab Backend MCP",
|
|
33
|
+
"description": "Deploy applications to GitLab and Coolify with two simple commands",
|
|
34
|
+
"tools": [
|
|
35
|
+
{
|
|
36
|
+
"name": "mlgym_user_create",
|
|
37
|
+
"description": "Create a new user with GitLab, Coolify, and SSH key setup"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "mlgym_project_init",
|
|
41
|
+
"description": "Initialize a project with GitLab repository and Coolify deployment"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
}
|
package/tests/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# MCP Server Test Suite
|
|
2
|
+
|
|
3
|
+
Comprehensive tests for all MCP server functions.
|
|
4
|
+
|
|
5
|
+
## Directory Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
tests/
|
|
9
|
+
├── README.md # This file
|
|
10
|
+
├── run-all-tests.sh # Master test runner
|
|
11
|
+
├── mlgym_auth_login_test.sh # ✅ 15 tests (auth_login)
|
|
12
|
+
├── mlgym_user_create_test.sh # ✅ 20 tests (user_create)
|
|
13
|
+
├── mlgym_auth_logout_test.sh # ✅ 8 tests (auth_logout)
|
|
14
|
+
├── mlgym_project_init_test.sh # ✅ 6 tests (project_init)
|
|
15
|
+
├── mlgym_projects_list_test.sh # ✅ 6 tests (projects_list)
|
|
16
|
+
└── mlgym_projects_get_test.sh # ✅ 7 tests (projects_get)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Running Tests
|
|
20
|
+
|
|
21
|
+
### Run All Tests
|
|
22
|
+
```bash
|
|
23
|
+
cd mcp-server
|
|
24
|
+
./tests/run-all-tests.sh
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Run Individual Test
|
|
28
|
+
```bash
|
|
29
|
+
cd mcp-server
|
|
30
|
+
./tests/mlgym_auth_login_test.sh
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Test Coverage
|
|
34
|
+
|
|
35
|
+
### Completed (6 functions, 62 total tests)
|
|
36
|
+
- ✅ **mlgym_auth_login** (15 tests)
|
|
37
|
+
- Valid/invalid credentials, SQL injection, XSS, buffer overflow, token storage
|
|
38
|
+
- ✅ **mlgym_user_create** (20 tests)
|
|
39
|
+
- Required fields, validation, security, SSH key generation, duplicates
|
|
40
|
+
- ✅ **mlgym_auth_logout** (8 tests)
|
|
41
|
+
- Session cleanup, double logout, config file deletion
|
|
42
|
+
- ✅ **mlgym_project_init** (6 tests)
|
|
43
|
+
- Project creation, deployment setup, webhook configuration
|
|
44
|
+
- ✅ **mlgym_projects_list** (6 tests)
|
|
45
|
+
- List projects, user isolation, response format
|
|
46
|
+
- ✅ **mlgym_projects_get** (7 tests)
|
|
47
|
+
- Get project details, validation, non-existent projects
|
|
48
|
+
|
|
49
|
+
### Remaining (37 functions)
|
|
50
|
+
See TODO.md for priority order and testing plan.
|
|
51
|
+
|
|
52
|
+
## Test Format
|
|
53
|
+
|
|
54
|
+
Each test file follows this structure:
|
|
55
|
+
```bash
|
|
56
|
+
#!/bin/bash
|
|
57
|
+
set -e
|
|
58
|
+
|
|
59
|
+
PASSED=0
|
|
60
|
+
FAILED=0
|
|
61
|
+
|
|
62
|
+
# Test 1: Description
|
|
63
|
+
if [condition]; then
|
|
64
|
+
echo "✅ Test 1: Description"
|
|
65
|
+
PASSED=$((PASSED + 1))
|
|
66
|
+
else
|
|
67
|
+
echo "❌ Test 1: Description"
|
|
68
|
+
FAILED=$((FAILED + 1))
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
# Final summary
|
|
72
|
+
echo "RESULTS: $PASSED passed, $FAILED failed"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Test Categories
|
|
76
|
+
|
|
77
|
+
Each test file covers:
|
|
78
|
+
1. **Authentication** - Verify auth requirements
|
|
79
|
+
2. **Validation** - Required/optional parameters
|
|
80
|
+
3. **Edge Cases** - Empty strings, null values, extreme inputs
|
|
81
|
+
4. **Security** - SQL injection, XSS, buffer overflow
|
|
82
|
+
5. **Functional** - Core functionality with real API calls
|
|
83
|
+
6. **Error Handling** - Invalid inputs, missing data
|
|
84
|
+
|
|
85
|
+
## Requirements
|
|
86
|
+
|
|
87
|
+
- Node.js with MCP server running
|
|
88
|
+
- Backend server at https://backend.eu.ezb.net
|
|
89
|
+
- jq for JSON parsing
|
|
90
|
+
- bash 4.0+
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Comprehensive test suite for mlgym_auth_login
|
|
3
|
+
# Tests functional requirements, edge cases, and security
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
TEST_EMAIL="fulltest-$(date +%s)@example.com"
|
|
8
|
+
TEST_PASS="MyV3ryC0mpl3x!P@ssw0rd#2024"
|
|
9
|
+
PASSED=0
|
|
10
|
+
FAILED=0
|
|
11
|
+
|
|
12
|
+
echo "=== mlgym_auth_login Comprehensive Test Suite ==="
|
|
13
|
+
echo ""
|
|
14
|
+
|
|
15
|
+
# Setup: Create test user
|
|
16
|
+
echo "[SETUP] Creating test user: $TEST_EMAIL"
|
|
17
|
+
CREATE_REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_user_create\",\"arguments\":{\"email\":\"$TEST_EMAIL\",\"name\":\"Full Test User\",\"password\":\"$TEST_PASS\",\"accept_terms\":true}},\"id\":1}"
|
|
18
|
+
RESP=$(echo "$CREATE_REQ" | node index.js 2>/dev/null | tail -1)
|
|
19
|
+
USER_ID=$(echo "$RESP" | jq -r '.result.content[0].text' | jq -r '.user_id')
|
|
20
|
+
if [ -n "$USER_ID" ] && [ "$USER_ID" != "null" ]; then
|
|
21
|
+
echo "✅ Test user created (ID: $USER_ID)"
|
|
22
|
+
else
|
|
23
|
+
echo "❌ Failed to create test user"
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
echo ""
|
|
27
|
+
|
|
28
|
+
# Helper to run test
|
|
29
|
+
run_test() {
|
|
30
|
+
local test_name="$1"
|
|
31
|
+
local email="$2"
|
|
32
|
+
local password="$3"
|
|
33
|
+
local expected_status="$4"
|
|
34
|
+
|
|
35
|
+
local req="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_auth_login\",\"arguments\":{\"email\":\"$email\",\"password\":\"$password\"}},\"id\":99}"
|
|
36
|
+
local resp=$(echo "$req" | node index.js 2>/dev/null | tail -1)
|
|
37
|
+
local status=$(echo "$resp" | jq -r '.result.content[0].text' | jq -r '.status')
|
|
38
|
+
|
|
39
|
+
if [ "$status" = "$expected_status" ]; then
|
|
40
|
+
echo "✅ $test_name"
|
|
41
|
+
PASSED=$((PASSED + 1))
|
|
42
|
+
else
|
|
43
|
+
echo "❌ $test_name (expected: $expected_status, got: $status)"
|
|
44
|
+
FAILED=$((FAILED + 1))
|
|
45
|
+
fi
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# Test 1: Valid login
|
|
49
|
+
run_test "Test 1: Valid login" "$TEST_EMAIL" "$TEST_PASS" "success"
|
|
50
|
+
|
|
51
|
+
# Test 2: Wrong password
|
|
52
|
+
run_test "Test 2: Wrong password" "$TEST_EMAIL" "WrongPass123!" "error"
|
|
53
|
+
|
|
54
|
+
# Test 3: Non-existent user
|
|
55
|
+
run_test "Test 3: Non-existent user" "fake999@example.com" "Pass123!" "error"
|
|
56
|
+
|
|
57
|
+
# Test 4: Empty email
|
|
58
|
+
run_test "Test 4: Empty email" "" "$TEST_PASS" "error"
|
|
59
|
+
|
|
60
|
+
# Test 5: Empty password
|
|
61
|
+
run_test "Test 5: Empty password" "$TEST_EMAIL" "" "error"
|
|
62
|
+
|
|
63
|
+
# Test 6: Invalid email format
|
|
64
|
+
run_test "Test 6: Invalid email format" "not-an-email" "Pass123!" "error"
|
|
65
|
+
|
|
66
|
+
# Test 7: SQL injection in email
|
|
67
|
+
run_test "Test 7: SQL injection (email)" "admin@test.com OR 1=1--" "Pass123!" "error"
|
|
68
|
+
|
|
69
|
+
# Test 8: SQL injection in password
|
|
70
|
+
run_test "Test 8: SQL injection (password)" "$TEST_EMAIL" "' OR '1'='1" "error"
|
|
71
|
+
|
|
72
|
+
# Test 9: XSS attempt
|
|
73
|
+
run_test "Test 9: XSS attempt" "<script>alert(1)</script>@test.com" "Pass123!" "error"
|
|
74
|
+
|
|
75
|
+
# Test 10: Missing password parameter
|
|
76
|
+
echo "Test 10: Missing password parameter"
|
|
77
|
+
REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_auth_login\",\"arguments\":{\"email\":\"$TEST_EMAIL\"}},\"id\":100}"
|
|
78
|
+
RESP=$(echo "$REQ" | node index.js 2>/dev/null | tail -1)
|
|
79
|
+
STATUS=$(echo "$RESP" | jq -r '.result.content[0].text' | jq -r '.status')
|
|
80
|
+
if [ "$STATUS" = "error" ]; then
|
|
81
|
+
echo "✅ Test 10: Missing password"
|
|
82
|
+
PASSED=$((PASSED + 1))
|
|
83
|
+
else
|
|
84
|
+
echo "❌ Test 10: Should reject missing password"
|
|
85
|
+
FAILED=$((FAILED + 1))
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# Test 11: Missing email parameter
|
|
89
|
+
echo "Test 11: Missing email parameter"
|
|
90
|
+
REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_auth_login\",\"arguments\":{\"password\":\"$TEST_PASS\"}},\"id\":101}"
|
|
91
|
+
RESP=$(echo "$REQ" | node index.js 2>/dev/null | tail -1)
|
|
92
|
+
STATUS=$(echo "$RESP" | jq -r '.result.content[0].text' | jq -r '.status')
|
|
93
|
+
if [ "$STATUS" = "error" ]; then
|
|
94
|
+
echo "✅ Test 11: Missing email"
|
|
95
|
+
PASSED=$((PASSED + 1))
|
|
96
|
+
else
|
|
97
|
+
echo "❌ Test 11: Should reject missing email"
|
|
98
|
+
FAILED=$((FAILED + 1))
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Test 12: Token storage
|
|
102
|
+
echo "Test 12: Token storage verification"
|
|
103
|
+
if [ -f ~/.mlgym/mcp_config.json ]; then
|
|
104
|
+
TOKEN=$(jq -r '.token' ~/.mlgym/mcp_config.json)
|
|
105
|
+
EMAIL=$(jq -r '.email' ~/.mlgym/mcp_config.json)
|
|
106
|
+
if [ -n "$TOKEN" ] && [ "$TOKEN" != "null" ] && [ "$EMAIL" = "$TEST_EMAIL" ]; then
|
|
107
|
+
echo "✅ Test 12: Token stored correctly"
|
|
108
|
+
PASSED=$((PASSED + 1))
|
|
109
|
+
else
|
|
110
|
+
echo "❌ Test 12: Token not stored properly"
|
|
111
|
+
FAILED=$((FAILED + 1))
|
|
112
|
+
fi
|
|
113
|
+
else
|
|
114
|
+
echo "❌ Test 12: Config file not created"
|
|
115
|
+
FAILED=$((FAILED + 1))
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
# Test 13: Response format validation
|
|
119
|
+
echo "Test 13: Response format validation"
|
|
120
|
+
REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_auth_login\",\"arguments\":{\"email\":\"$TEST_EMAIL\",\"password\":\"$TEST_PASS\"}},\"id\":102}"
|
|
121
|
+
RESP=$(echo "$REQ" | node index.js 2>/dev/null | tail -1)
|
|
122
|
+
CONTENT=$(echo "$RESP" | jq -r '.result.content[0].text')
|
|
123
|
+
HAS_STATUS=$(echo "$CONTENT" | jq -e '.status' > /dev/null 2>&1 && echo "yes" || echo "no")
|
|
124
|
+
HAS_TOKEN=$(echo "$CONTENT" | jq -e '.token' > /dev/null 2>&1 && echo "yes" || echo "no")
|
|
125
|
+
HAS_USER=$(echo "$CONTENT" | jq -e '.user.email' > /dev/null 2>&1 && echo "yes" || echo "no")
|
|
126
|
+
if [ "$HAS_STATUS" = "yes" ] && [ "$HAS_TOKEN" = "yes" ] && [ "$HAS_USER" = "yes" ]; then
|
|
127
|
+
echo "✅ Test 13: Response format valid"
|
|
128
|
+
PASSED=$((PASSED + 1))
|
|
129
|
+
else
|
|
130
|
+
echo "❌ Test 13: Response format invalid (status:$HAS_STATUS, token:$HAS_TOKEN, user:$HAS_USER)"
|
|
131
|
+
FAILED=$((FAILED + 1))
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
# Test 14: User data accuracy
|
|
135
|
+
echo "Test 14: User data accuracy"
|
|
136
|
+
USER_EMAIL=$(echo "$CONTENT" | jq -r '.user.email')
|
|
137
|
+
if [ "$USER_EMAIL" = "$TEST_EMAIL" ]; then
|
|
138
|
+
echo "✅ Test 14: User data correct"
|
|
139
|
+
PASSED=$((PASSED + 1))
|
|
140
|
+
else
|
|
141
|
+
echo "❌ Test 14: User data mismatch"
|
|
142
|
+
FAILED=$((FAILED + 1))
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
# Test 15: Buffer overflow attempt
|
|
146
|
+
echo "Test 15: Buffer overflow (very long input)"
|
|
147
|
+
LONG_EMAIL=$(python3 -c "print('a' * 10000 + '@test.com')")
|
|
148
|
+
REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_auth_login\",\"arguments\":{\"email\":\"$LONG_EMAIL\",\"password\":\"Pass123!\"}},\"id\":103}"
|
|
149
|
+
RESP=$(echo "$REQ" | node index.js 2>/dev/null | tail -1)
|
|
150
|
+
STATUS=$(echo "$RESP" | jq -r '.result.content[0].text' | jq -r '.status')
|
|
151
|
+
if [ "$STATUS" = "error" ]; then
|
|
152
|
+
echo "✅ Test 15: Buffer overflow prevented"
|
|
153
|
+
PASSED=$((PASSED + 1))
|
|
154
|
+
else
|
|
155
|
+
echo "⚠️ Test 15: Long input accepted (may be vulnerability)"
|
|
156
|
+
FAILED=$((FAILED + 1))
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
echo ""
|
|
160
|
+
echo "==============================================="
|
|
161
|
+
echo "RESULTS: $PASSED passed, $FAILED failed (Total: $((PASSED + FAILED)))"
|
|
162
|
+
echo "==============================================="
|
|
163
|
+
|
|
164
|
+
if [ $FAILED -eq 0 ]; then
|
|
165
|
+
echo "✅ ALL TESTS PASSED"
|
|
166
|
+
exit 0
|
|
167
|
+
else
|
|
168
|
+
echo "⚠️ SOME TESTS FAILED"
|
|
169
|
+
exit 1
|
|
170
|
+
fi
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Comprehensive test suite for mlgym_auth_logout
|
|
3
|
+
# Tests functional requirements, edge cases, and security
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
PASSED=0
|
|
8
|
+
FAILED=0
|
|
9
|
+
|
|
10
|
+
echo "=== mlgym_auth_logout Comprehensive Test Suite ==="
|
|
11
|
+
echo ""
|
|
12
|
+
|
|
13
|
+
# Test 1: Logout without active session
|
|
14
|
+
echo "Test 1: Logout without active session"
|
|
15
|
+
rm -f ~/.mlgym/mcp_config.json
|
|
16
|
+
REQ='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"mlgym_auth_logout","arguments":{}},"id":1}'
|
|
17
|
+
RESP=$(echo "$REQ" | node index.js 2>/dev/null | tail -1)
|
|
18
|
+
CONTENT=$(echo "$RESP" | jq -r '.result.content[0].text')
|
|
19
|
+
STATUS=$(echo "$CONTENT" | jq -r '.status')
|
|
20
|
+
if [ "$STATUS" = "info" ] || echo "$CONTENT" | grep -q "No active session"; then
|
|
21
|
+
echo "✅ Test 1: Correctly handles no session"
|
|
22
|
+
PASSED=$((PASSED + 1))
|
|
23
|
+
else
|
|
24
|
+
echo "❌ Test 1: Should return info status for no session"
|
|
25
|
+
FAILED=$((FAILED + 1))
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Test 2-5: Logout with active session (create user first)
|
|
29
|
+
echo "Test 2-5: Logout with active session"
|
|
30
|
+
# Create user to get a session
|
|
31
|
+
TEST_EMAIL="logouttest-$(date +%s)@example.com"
|
|
32
|
+
CREATE_REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_user_create\",\"arguments\":{\"email\":\"$TEST_EMAIL\",\"name\":\"Logout Test User\",\"password\":\"MyV3ryC0mpl3x!P@ssw0rd#2024\",\"accept_terms\":true}},\"id\":2}"
|
|
33
|
+
CREATE_RESP=$(echo "$CREATE_REQ" | node index.js 2>/dev/null | tail -1)
|
|
34
|
+
USER_ID=$(echo "$CREATE_RESP" | jq -r '.result.content[0].text' | jq -r '.user_id')
|
|
35
|
+
|
|
36
|
+
if [ -n "$USER_ID" ] && [ "$USER_ID" != "null" ]; then
|
|
37
|
+
# Now logout
|
|
38
|
+
LOGOUT_REQ='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"mlgym_auth_logout","arguments":{}},"id":3}'
|
|
39
|
+
LOGOUT_RESP=$(echo "$LOGOUT_REQ" | node index.js 2>/dev/null | tail -1)
|
|
40
|
+
LOGOUT_CONTENT=$(echo "$LOGOUT_RESP" | jq -r '.result.content[0].text')
|
|
41
|
+
LOGOUT_STATUS=$(echo "$LOGOUT_CONTENT" | jq -r '.status')
|
|
42
|
+
|
|
43
|
+
# Test 2: Logout status
|
|
44
|
+
if [ "$LOGOUT_STATUS" = "success" ]; then
|
|
45
|
+
echo "✅ Test 2: Logout successful"
|
|
46
|
+
PASSED=$((PASSED + 1))
|
|
47
|
+
else
|
|
48
|
+
echo "❌ Test 2: Logout should return success status"
|
|
49
|
+
FAILED=$((FAILED + 1))
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Test 3: Config file deletion
|
|
53
|
+
echo "Test 3: Config file deletion after logout"
|
|
54
|
+
if [ ! -f ~/.mlgym/mcp_config.json ]; then
|
|
55
|
+
echo "✅ Test 3: Config file deleted"
|
|
56
|
+
PASSED=$((PASSED + 1))
|
|
57
|
+
else
|
|
58
|
+
echo "❌ Test 3: Config file should be deleted after logout"
|
|
59
|
+
FAILED=$((FAILED + 1))
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Test 4: Response format validation
|
|
63
|
+
echo "Test 4: Response format validation"
|
|
64
|
+
HAS_STATUS=$(echo "$LOGOUT_CONTENT" | jq -e '.status' > /dev/null 2>&1 && echo "yes" || echo "no")
|
|
65
|
+
HAS_MESSAGE=$(echo "$LOGOUT_CONTENT" | jq -e '.message' > /dev/null 2>&1 && echo "yes" || echo "no")
|
|
66
|
+
HAS_PREV_USER=$(echo "$LOGOUT_CONTENT" | jq -e '.previous_user' > /dev/null 2>&1 && echo "yes" || echo "no")
|
|
67
|
+
|
|
68
|
+
if [ "$HAS_STATUS" = "yes" ] && [ "$HAS_MESSAGE" = "yes" ] && [ "$HAS_PREV_USER" = "yes" ]; then
|
|
69
|
+
echo "✅ Test 4: Response format valid"
|
|
70
|
+
PASSED=$((PASSED + 1))
|
|
71
|
+
else
|
|
72
|
+
echo "❌ Test 4: Response format invalid (status:$HAS_STATUS, message:$HAS_MESSAGE, previous_user:$HAS_PREV_USER)"
|
|
73
|
+
FAILED=$((FAILED + 1))
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# Test 5: Previous user email verification
|
|
77
|
+
echo "Test 5: Previous user email verification"
|
|
78
|
+
PREV_USER=$(echo "$LOGOUT_CONTENT" | jq -r '.previous_user')
|
|
79
|
+
if [ "$PREV_USER" = "$TEST_EMAIL" ]; then
|
|
80
|
+
echo "✅ Test 5: Previous user email correct"
|
|
81
|
+
PASSED=$((PASSED + 1))
|
|
82
|
+
else
|
|
83
|
+
echo "❌ Test 5: Previous user email mismatch (expected: $TEST_EMAIL, got: $PREV_USER)"
|
|
84
|
+
FAILED=$((FAILED + 1))
|
|
85
|
+
fi
|
|
86
|
+
else
|
|
87
|
+
echo "⚠️ Tests 2-5: Couldn't create user for logout test"
|
|
88
|
+
FAILED=$((FAILED + 4))
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# Test 6: Double logout (logout twice)
|
|
92
|
+
echo "Test 6: Double logout (already logged out)"
|
|
93
|
+
DOUBLE_LOGOUT=$(echo "$LOGOUT_REQ" | node index.js 2>/dev/null | tail -1)
|
|
94
|
+
DOUBLE_CONTENT=$(echo "$DOUBLE_LOGOUT" | jq -r '.result.content[0].text')
|
|
95
|
+
DOUBLE_STATUS=$(echo "$DOUBLE_CONTENT" | jq -r '.status')
|
|
96
|
+
|
|
97
|
+
if [ "$DOUBLE_STATUS" = "info" ] || echo "$DOUBLE_CONTENT" | grep -q "No active session"; then
|
|
98
|
+
echo "✅ Test 6: Double logout handled correctly"
|
|
99
|
+
PASSED=$((PASSED + 1))
|
|
100
|
+
else
|
|
101
|
+
echo "❌ Test 6: Should return info status for double logout"
|
|
102
|
+
FAILED=$((FAILED + 1))
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# Test 7: Login after logout
|
|
106
|
+
echo "Test 7: Login after logout verification"
|
|
107
|
+
# Create user again (fresh session)
|
|
108
|
+
FRESH_EMAIL="fresh-$(date +%s)@example.com"
|
|
109
|
+
FRESH_PASS="MyV3ryC0mpl3x!P@ssw0rd#2024"
|
|
110
|
+
FRESH_CREATE="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_user_create\",\"arguments\":{\"email\":\"$FRESH_EMAIL\",\"name\":\"Fresh User\",\"password\":\"$FRESH_PASS\",\"accept_terms\":true}},\"id\":7}"
|
|
111
|
+
FRESH_RESP=$(echo "$FRESH_CREATE" | node index.js 2>/dev/null | tail -1)
|
|
112
|
+
|
|
113
|
+
# Logout
|
|
114
|
+
FRESH_LOGOUT='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"mlgym_auth_logout","arguments":{}},"id":8}'
|
|
115
|
+
echo "$FRESH_LOGOUT" | node index.js 2>/dev/null > /dev/null
|
|
116
|
+
|
|
117
|
+
# Try to login again
|
|
118
|
+
LOGIN_REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_auth_login\",\"arguments\":{\"email\":\"$FRESH_EMAIL\",\"password\":\"$FRESH_PASS\"}},\"id\":9}"
|
|
119
|
+
LOGIN_RESP=$(echo "$LOGIN_REQ" | node index.js 2>/dev/null | tail -1)
|
|
120
|
+
LOGIN_CONTENT=$(echo "$LOGIN_RESP" | jq -r '.result.content[0].text')
|
|
121
|
+
LOGIN_STATUS=$(echo "$LOGIN_CONTENT" | jq -r '.status')
|
|
122
|
+
|
|
123
|
+
if [ "$LOGIN_STATUS" = "success" ]; then
|
|
124
|
+
echo "✅ Test 7: Can login after logout"
|
|
125
|
+
PASSED=$((PASSED + 1))
|
|
126
|
+
else
|
|
127
|
+
echo "❌ Test 7: Should be able to login after logout"
|
|
128
|
+
FAILED=$((FAILED + 1))
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
# Test 8: Extra parameters ignored
|
|
132
|
+
echo "Test 8: Extra parameters ignored gracefully"
|
|
133
|
+
EXTRA_REQ='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"mlgym_auth_logout","arguments":{"extra_param":"should_be_ignored"}},"id":10}'
|
|
134
|
+
EXTRA_RESP=$(echo "$EXTRA_REQ" | node index.js 2>/dev/null | tail -1)
|
|
135
|
+
EXTRA_CONTENT=$(echo "$EXTRA_RESP" | jq -r '.result.content[0].text')
|
|
136
|
+
EXTRA_STATUS=$(echo "$EXTRA_CONTENT" | jq -r '.status')
|
|
137
|
+
|
|
138
|
+
if [ "$EXTRA_STATUS" = "success" ]; then
|
|
139
|
+
echo "✅ Test 8: Extra parameters ignored"
|
|
140
|
+
PASSED=$((PASSED + 1))
|
|
141
|
+
else
|
|
142
|
+
echo "❌ Test 8: Should handle extra parameters gracefully"
|
|
143
|
+
FAILED=$((FAILED + 1))
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
echo ""
|
|
147
|
+
echo "==============================================="
|
|
148
|
+
echo "RESULTS: $PASSED passed, $FAILED failed (Total: $((PASSED + FAILED)))"
|
|
149
|
+
echo "==============================================="
|
|
150
|
+
|
|
151
|
+
if [ $FAILED -eq 0 ]; then
|
|
152
|
+
echo "✅ ALL TESTS PASSED"
|
|
153
|
+
exit 0
|
|
154
|
+
else
|
|
155
|
+
echo "⚠️ SOME TESTS FAILED"
|
|
156
|
+
exit 1
|
|
157
|
+
fi
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Comprehensive test suite for deployment functions:
|
|
3
|
+
# - mlgym_deployments_trigger
|
|
4
|
+
# - mlgym_deployments_get_status
|
|
5
|
+
# - mlgym_deployments_list
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
PASSED=0
|
|
10
|
+
FAILED=0
|
|
11
|
+
|
|
12
|
+
echo "=== MCP Deployment Functions Test Suite ==="
|
|
13
|
+
echo ""
|
|
14
|
+
|
|
15
|
+
# Setup: Create user and project with deployment
|
|
16
|
+
echo "[SETUP] Creating test user and project with deployment"
|
|
17
|
+
TEST_EMAIL="deploy-$(date +%s)@example.com"
|
|
18
|
+
TEST_PASS="MyV3ryC0mpl3x!P@ssw0rd#2024"
|
|
19
|
+
CREATE_REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_user_create\",\"arguments\":{\"email\":\"$TEST_EMAIL\",\"name\":\"Deploy Test\",\"password\":\"$TEST_PASS\",\"accept_terms\":true}},\"id\":1}"
|
|
20
|
+
CREATE_RESP=$(echo "$CREATE_REQ" | node index.js 2>/dev/null | tail -1)
|
|
21
|
+
USER_ID=$(echo "$CREATE_RESP" | jq -r '.result.content[0].text' | jq -r '.user_id')
|
|
22
|
+
|
|
23
|
+
if [ -n "$USER_ID" ] && [ "$USER_ID" != "null" ]; then
|
|
24
|
+
echo "✅ Test user created (ID: $USER_ID)"
|
|
25
|
+
else
|
|
26
|
+
echo "❌ Failed to create test user"
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Create project WITH deployment enabled
|
|
31
|
+
PROJECT_NAME="deploy-test-$(date +%s | tail -c 6)"
|
|
32
|
+
PROJ_REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_project_init\",\"arguments\":{\"name\":\"$PROJECT_NAME\",\"description\":\"Test project with deployment\",\"enable_deployment\":true}},\"id\":2}"
|
|
33
|
+
PROJ_RESP=$(echo "$PROJ_REQ" | node index.js 2>/dev/null | tail -1)
|
|
34
|
+
PROJ_CONTENT=$(echo "$PROJ_RESP" | jq -r '.result.content[0].text')
|
|
35
|
+
PROJECT_ID=$(echo "$PROJ_CONTENT" | jq -r '.project_id' 2>/dev/null)
|
|
36
|
+
|
|
37
|
+
if [ -n "$PROJECT_ID" ] && [ "$PROJECT_ID" != "null" ]; then
|
|
38
|
+
echo "✅ Test project with deployment created (ID: $PROJECT_ID)"
|
|
39
|
+
else
|
|
40
|
+
echo "❌ Failed to create test project"
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
## TRIGGER DEPLOYMENT TESTS ##
|
|
45
|
+
echo ""
|
|
46
|
+
echo "=== mlgym_deployments_trigger Tests ==="
|
|
47
|
+
echo ""
|
|
48
|
+
|
|
49
|
+
# Test 1: Trigger without authentication
|
|
50
|
+
echo "Test 1: Trigger deployment without authentication"
|
|
51
|
+
rm -f ~/.mlgym/mcp_config.json
|
|
52
|
+
REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_deployments_trigger\",\"arguments\":{\"project_id\":$PROJECT_ID}},\"id\":3}"
|
|
53
|
+
RESP=$(echo "$REQ" | node index.js 2>/dev/null | tail -1)
|
|
54
|
+
CONTENT=$(echo "$RESP" | jq -r '.result.content[0].text')
|
|
55
|
+
STATUS=$(echo "$CONTENT" | jq -r '.status')
|
|
56
|
+
|
|
57
|
+
if [ "$STATUS" = "error" ] && echo "$CONTENT" | grep -q "Not authenticated"; then
|
|
58
|
+
echo "✅ Test 1: Correctly requires authentication"
|
|
59
|
+
PASSED=$((PASSED + 1))
|
|
60
|
+
else
|
|
61
|
+
echo "❌ Test 1: Should require authentication"
|
|
62
|
+
FAILED=$((FAILED + 1))
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Re-login
|
|
66
|
+
LOGIN_REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_auth_login\",\"arguments\":{\"email\":\"$TEST_EMAIL\",\"password\":\"$TEST_PASS\"}},\"id\":4}"
|
|
67
|
+
echo "$LOGIN_REQ" | node index.js 2>/dev/null > /dev/null
|
|
68
|
+
|
|
69
|
+
# Test 2: Missing project_id
|
|
70
|
+
echo "Test 2: Trigger deployment without project_id"
|
|
71
|
+
REQ='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"mlgym_deployments_trigger","arguments":{}},"id":5}'
|
|
72
|
+
RESP=$(echo "$REQ" | node index.js 2>/dev/null | tail -1)
|
|
73
|
+
CONTENT=$(echo "$RESP" | jq -r '.result.content[0].text')
|
|
74
|
+
STATUS=$(echo "$CONTENT" | jq -r '.status')
|
|
75
|
+
|
|
76
|
+
if [ "$STATUS" = "error" ] && echo "$CONTENT" | grep -q "required"; then
|
|
77
|
+
echo "✅ Test 2: Correctly validates missing project_id"
|
|
78
|
+
PASSED=$((PASSED + 1))
|
|
79
|
+
else
|
|
80
|
+
echo "❌ Test 2: Should require project_id"
|
|
81
|
+
FAILED=$((FAILED + 1))
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# Test 3: Trigger deployment with valid project
|
|
85
|
+
echo "Test 3: Trigger deployment with valid project"
|
|
86
|
+
TRIGGER_REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_deployments_trigger\",\"arguments\":{\"project_id\":$PROJECT_ID}},\"id\":6}"
|
|
87
|
+
TRIGGER_RESP=$(echo "$TRIGGER_REQ" | node index.js 2>/dev/null | tail -1)
|
|
88
|
+
TRIGGER_CONTENT=$(echo "$TRIGGER_RESP" | jq -r '.result.content[0].text')
|
|
89
|
+
TRIGGER_STATUS=$(echo "$TRIGGER_CONTENT" | jq -r '.status')
|
|
90
|
+
|
|
91
|
+
DEPLOYMENT_ID=""
|
|
92
|
+
if [ "$TRIGGER_STATUS" = "success" ]; then
|
|
93
|
+
DEPLOYMENT_ID=$(echo "$TRIGGER_CONTENT" | jq -r '.deployment_id')
|
|
94
|
+
echo "✅ Test 3: Deployment triggered (ID: $DEPLOYMENT_ID)"
|
|
95
|
+
PASSED=$((PASSED + 1))
|
|
96
|
+
else
|
|
97
|
+
echo "❌ Test 3: Deployment trigger failed - $(echo "$TRIGGER_CONTENT" | jq -r '.message')"
|
|
98
|
+
FAILED=$((FAILED + 1))
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
## GET STATUS TESTS ##
|
|
102
|
+
echo ""
|
|
103
|
+
echo "=== mlgym_deployments_get_status Tests ==="
|
|
104
|
+
echo ""
|
|
105
|
+
|
|
106
|
+
# Test 4: Get status without parameters
|
|
107
|
+
echo "Test 4: Get status without parameters"
|
|
108
|
+
REQ='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"mlgym_deployments_get_status","arguments":{}},"id":7}'
|
|
109
|
+
RESP=$(echo "$REQ" | node index.js 2>/dev/null | tail -1)
|
|
110
|
+
CONTENT=$(echo "$RESP" | jq -r '.result.content[0].text')
|
|
111
|
+
STATUS=$(echo "$CONTENT" | jq -r '.status')
|
|
112
|
+
|
|
113
|
+
if [ "$STATUS" = "error" ]; then
|
|
114
|
+
echo "✅ Test 4: Correctly requires deployment_id or project_id"
|
|
115
|
+
PASSED=$((PASSED + 1))
|
|
116
|
+
else
|
|
117
|
+
echo "❌ Test 4: Should require at least one parameter"
|
|
118
|
+
FAILED=$((FAILED + 1))
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
# Test 5: Get status with project_id
|
|
122
|
+
if [ -n "$PROJECT_ID" ]; then
|
|
123
|
+
echo "Test 5: Get status with project_id"
|
|
124
|
+
STATUS_REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_deployments_get_status\",\"arguments\":{\"project_id\":$PROJECT_ID}},\"id\":8}"
|
|
125
|
+
STATUS_RESP=$(echo "$STATUS_REQ" | node index.js 2>/dev/null | tail -1)
|
|
126
|
+
STATUS_CONTENT=$(echo "$STATUS_RESP" | jq -r '.result.content[0].text')
|
|
127
|
+
STATUS_STATUS=$(echo "$STATUS_CONTENT" | jq -r '.status')
|
|
128
|
+
|
|
129
|
+
if [ "$STATUS_STATUS" = "success" ] || [ "$STATUS_STATUS" = "error" ]; then
|
|
130
|
+
echo "✅ Test 5: Get status returned response"
|
|
131
|
+
PASSED=$((PASSED + 1))
|
|
132
|
+
else
|
|
133
|
+
echo "❌ Test 5: Get status failed"
|
|
134
|
+
FAILED=$((FAILED + 1))
|
|
135
|
+
fi
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
## LIST DEPLOYMENTS TESTS ##
|
|
139
|
+
echo ""
|
|
140
|
+
echo "=== mlgym_deployments_list Tests ==="
|
|
141
|
+
echo ""
|
|
142
|
+
|
|
143
|
+
# Test 6: List deployments without authentication
|
|
144
|
+
echo "Test 6: List deployments without authentication"
|
|
145
|
+
rm -f ~/.mlgym/mcp_config.json
|
|
146
|
+
REQ='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"mlgym_deployments_list","arguments":{}},"id":9}'
|
|
147
|
+
RESP=$(echo "$REQ" | node index.js 2>/dev/null | tail -1)
|
|
148
|
+
CONTENT=$(echo "$RESP" | jq -r '.result.content[0].text')
|
|
149
|
+
STATUS=$(echo "$CONTENT" | jq -r '.status')
|
|
150
|
+
|
|
151
|
+
if [ "$STATUS" = "error" ] && echo "$CONTENT" | grep -q "Not authenticated"; then
|
|
152
|
+
echo "✅ Test 6: Correctly requires authentication"
|
|
153
|
+
PASSED=$((PASSED + 1))
|
|
154
|
+
else
|
|
155
|
+
echo "❌ Test 6: Should require authentication"
|
|
156
|
+
FAILED=$((FAILED + 1))
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
# Re-login
|
|
160
|
+
echo "$LOGIN_REQ" | node index.js 2>/dev/null > /dev/null
|
|
161
|
+
|
|
162
|
+
# Test 7: List all deployments
|
|
163
|
+
echo "Test 7: List all deployments"
|
|
164
|
+
LIST_REQ='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"mlgym_deployments_list","arguments":{}},"id":10}'
|
|
165
|
+
LIST_RESP=$(echo "$LIST_REQ" | node index.js 2>/dev/null | tail -1)
|
|
166
|
+
LIST_CONTENT=$(echo "$LIST_RESP" | jq -r '.result.content[0].text')
|
|
167
|
+
LIST_STATUS=$(echo "$LIST_CONTENT" | jq -r '.status')
|
|
168
|
+
|
|
169
|
+
if [ "$LIST_STATUS" = "success" ]; then
|
|
170
|
+
DEPLOY_COUNT=$(echo "$LIST_CONTENT" | jq -r '.total' 2>/dev/null)
|
|
171
|
+
echo "✅ Test 7: List deployments successful (count: $DEPLOY_COUNT)"
|
|
172
|
+
PASSED=$((PASSED + 1))
|
|
173
|
+
else
|
|
174
|
+
echo "❌ Test 7: List deployments failed"
|
|
175
|
+
FAILED=$((FAILED + 1))
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
# Test 8: List deployments for specific project
|
|
179
|
+
echo "Test 8: List deployments for specific project"
|
|
180
|
+
PROJ_LIST_REQ="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"mlgym_deployments_list\",\"arguments\":{\"project_id\":$PROJECT_ID}},\"id\":11}"
|
|
181
|
+
PROJ_LIST_RESP=$(echo "$PROJ_LIST_REQ" | node index.js 2>/dev/null | tail -1)
|
|
182
|
+
PROJ_LIST_CONTENT=$(echo "$PROJ_LIST_RESP" | jq -r '.result.content[0].text')
|
|
183
|
+
PROJ_LIST_STATUS=$(echo "$PROJ_LIST_CONTENT" | jq -r '.status')
|
|
184
|
+
|
|
185
|
+
if [ "$PROJ_LIST_STATUS" = "success" ] || [ "$PROJ_LIST_STATUS" = "error" ]; then
|
|
186
|
+
echo "✅ Test 8: List project deployments returned response"
|
|
187
|
+
PASSED=$((PASSED + 1))
|
|
188
|
+
else
|
|
189
|
+
echo "❌ Test 8: List project deployments failed"
|
|
190
|
+
FAILED=$((FAILED + 1))
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
echo ""
|
|
194
|
+
echo "==============================================="
|
|
195
|
+
echo "RESULTS: $PASSED passed, $FAILED failed (Total: $((PASSED + FAILED)))"
|
|
196
|
+
echo "==============================================="
|
|
197
|
+
|
|
198
|
+
if [ $FAILED -eq 0 ]; then
|
|
199
|
+
echo "✅ ALL TESTS PASSED"
|
|
200
|
+
exit 0
|
|
201
|
+
else
|
|
202
|
+
echo "⚠️ SOME TESTS FAILED"
|
|
203
|
+
exit 1
|
|
204
|
+
fi
|