gitarsenal-cli 1.4.2 → 1.4.3
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/package.json +1 -1
- package/python/__pycache__/fetch_modal_tokens.cpython-313.pyc +0 -0
- package/python/__pycache__/modal_auth_patch.cpython-313.pyc +0 -0
- package/python/__pycache__/modal_token_solution.cpython-313.pyc +0 -0
- package/python/fetch_modal_tokens.py +66 -61
- package/python/test_modal_auth.py +2 -2
- package/python/MODAL_TOKEN_README.md +0 -77
- package/python/MODAL_TOKEN_SETUP.md +0 -82
package/package.json
CHANGED
Binary file
|
Binary file
|
Binary file
|
@@ -2,7 +2,7 @@
|
|
2
2
|
"""
|
3
3
|
Fetch Modal Tokens
|
4
4
|
|
5
|
-
This script fetches Modal tokens from the
|
5
|
+
This script fetches Modal tokens from the GitArsenal API.
|
6
6
|
"""
|
7
7
|
|
8
8
|
import os
|
@@ -13,92 +13,107 @@ import subprocess
|
|
13
13
|
from pathlib import Path
|
14
14
|
|
15
15
|
# Default tokens to use if we can't fetch from the server
|
16
|
-
DEFAULT_TOKEN_ID = "ak-sLhYqCjkvixiYcb9LAuCHp"
|
17
|
-
DEFAULT_TOKEN_SECRET = "as-fPzD0Zm0dl6IFAEkhaH9pq"
|
16
|
+
# DEFAULT_TOKEN_ID = "ak-sLhYqCjkvixiYcb9LAuCHp"
|
17
|
+
# DEFAULT_TOKEN_SECRET = "as-fPzD0Zm0dl6IFAEkhaH9pq"
|
18
18
|
|
19
|
-
def
|
19
|
+
def fetch_credentials_from_api(api_url=None, api_key=None, credential_id=None):
|
20
20
|
"""
|
21
|
-
Fetch
|
21
|
+
Fetch credentials from the GitArsenal API.
|
22
22
|
|
23
23
|
Args:
|
24
|
-
|
24
|
+
api_url: Base URL of the API (default: gitarsenal.dev)
|
25
25
|
api_key: API key for authentication
|
26
|
+
credential_id: Optional ID of specific credentials to fetch
|
26
27
|
|
27
28
|
Returns:
|
28
|
-
|
29
|
+
dict: Credentials containing modalTokenId and modalTokenSecret if successful, None otherwise
|
29
30
|
"""
|
30
31
|
# Use environment variables if not provided
|
31
|
-
if not
|
32
|
-
|
33
|
-
if
|
34
|
-
print(f"📋 Using
|
32
|
+
if not api_url:
|
33
|
+
api_url = os.environ.get("GITARSENAL_API_URL", "https://gitarsenal.dev")
|
34
|
+
if api_url:
|
35
|
+
print(f"📋 Using API URL from environment")
|
35
36
|
|
36
37
|
if not api_key:
|
37
|
-
api_key = os.environ.get("
|
38
|
+
api_key = os.environ.get("GITARSENAL_API_KEY")
|
38
39
|
if api_key:
|
39
40
|
print(f"📋 Using API key from environment (length: {len(api_key)})")
|
40
41
|
|
41
42
|
# Check if we have the necessary information
|
42
|
-
if not proxy_url:
|
43
|
-
# print("❌ No proxy URL provided or found in environment")
|
44
|
-
# print("💡 Set MODAL_PROXY_URL environment variable or use --proxy-url argument")
|
45
|
-
return None, None
|
46
|
-
|
47
43
|
if not api_key:
|
48
44
|
print("❌ No API key provided or found in environment")
|
49
|
-
|
50
|
-
return None
|
45
|
+
print("💡 Set GITARSENAL_API_KEY environment variable or use --api-key argument")
|
46
|
+
return None
|
51
47
|
|
52
48
|
# Ensure the URL ends with a slash
|
53
|
-
if not
|
54
|
-
|
49
|
+
if not api_url.endswith("/"):
|
50
|
+
api_url += "/"
|
51
|
+
|
52
|
+
# Add the endpoint for fetching credentials
|
53
|
+
credentials_url = f"{api_url}api/credentials"
|
55
54
|
|
56
|
-
# Add
|
57
|
-
|
55
|
+
# Add credential ID if provided
|
56
|
+
if credential_id:
|
57
|
+
credentials_url += f"?id={credential_id}"
|
58
58
|
|
59
59
|
try:
|
60
60
|
# Make the request
|
61
|
-
print(f"🔄 Fetching
|
61
|
+
print(f"🔄 Fetching credentials from GitArsenal API")
|
62
62
|
response = requests.get(
|
63
|
-
|
63
|
+
credentials_url,
|
64
64
|
headers={"X-API-Key": api_key}
|
65
65
|
)
|
66
66
|
|
67
67
|
# Check if the request was successful
|
68
68
|
if response.status_code == 200:
|
69
69
|
data = response.json()
|
70
|
-
token_id = data.get("
|
71
|
-
token_secret = data.get("
|
70
|
+
token_id = data.get("modalTokenId")
|
71
|
+
token_secret = data.get("modalTokenSecret")
|
72
|
+
openai_api_key = data.get("openaiApiKey")
|
72
73
|
|
73
74
|
if token_id and token_secret:
|
74
|
-
print("✅ Successfully fetched
|
75
|
-
return
|
75
|
+
print("✅ Successfully fetched credentials from GitArsenal API")
|
76
|
+
return {
|
77
|
+
"token_id": token_id,
|
78
|
+
"token_secret": token_secret,
|
79
|
+
"openai_api_key": openai_api_key
|
80
|
+
}
|
76
81
|
else:
|
77
|
-
print("❌
|
78
|
-
return None
|
82
|
+
print("❌ Modal tokens not found in response")
|
83
|
+
return None
|
79
84
|
else:
|
80
|
-
print(f"❌ Failed to fetch
|
81
|
-
return None
|
85
|
+
print(f"❌ Failed to fetch credentials: {response.status_code} - {response.text}")
|
86
|
+
return None
|
82
87
|
except Exception as e:
|
83
|
-
print(f"❌ Error fetching
|
84
|
-
return None
|
88
|
+
print(f"❌ Error fetching credentials: {e}")
|
89
|
+
return None
|
85
90
|
|
86
91
|
def get_tokens():
|
87
92
|
"""
|
88
|
-
Get Modal tokens, trying to fetch from the
|
93
|
+
Get Modal tokens, trying to fetch from the GitArsenal API first.
|
89
94
|
Also sets the tokens in environment variables.
|
90
95
|
|
91
96
|
Returns:
|
92
97
|
tuple: (token_id, token_secret)
|
93
98
|
"""
|
94
|
-
# Try to fetch from the
|
95
|
-
|
99
|
+
# Try to fetch from the API
|
100
|
+
credentials = fetch_credentials_from_api()
|
96
101
|
|
97
|
-
# If we couldn't fetch from the
|
98
|
-
if not
|
102
|
+
# If we couldn't fetch from the API, use the default tokens
|
103
|
+
if not credentials:
|
99
104
|
print("⚠️ Using default tokens")
|
100
105
|
token_id = DEFAULT_TOKEN_ID
|
101
106
|
token_secret = DEFAULT_TOKEN_SECRET
|
107
|
+
openai_api_key = None
|
108
|
+
else:
|
109
|
+
token_id = credentials["token_id"]
|
110
|
+
token_secret = credentials["token_secret"]
|
111
|
+
openai_api_key = credentials.get("openai_api_key")
|
112
|
+
|
113
|
+
# Set OpenAI API key if available
|
114
|
+
if openai_api_key:
|
115
|
+
os.environ["OPENAI_API_KEY"] = openai_api_key
|
116
|
+
print(f"✅ Set OPENAI_API_KEY environment variable")
|
102
117
|
|
103
118
|
# Set the tokens in environment variables
|
104
119
|
os.environ["MODAL_TOKEN_ID"] = token_id
|
@@ -111,33 +126,23 @@ if __name__ == "__main__":
|
|
111
126
|
# Parse command-line arguments if run directly
|
112
127
|
import argparse
|
113
128
|
|
114
|
-
parser = argparse.ArgumentParser(description='Fetch
|
115
|
-
parser.add_argument('--
|
116
|
-
parser.add_argument('--
|
129
|
+
parser = argparse.ArgumentParser(description='Fetch credentials from the GitArsenal API')
|
130
|
+
parser.add_argument('--api-url', help='Base URL of the GitArsenal API')
|
131
|
+
parser.add_argument('--api-key', help='API key for authentication')
|
132
|
+
parser.add_argument('--credential-id', help='ID of specific credentials to fetch')
|
117
133
|
args = parser.parse_args()
|
118
134
|
|
119
|
-
# Set
|
120
|
-
if args.
|
121
|
-
os.environ["
|
122
|
-
|
135
|
+
# Set API URL and API key in environment variables if provided
|
136
|
+
if args.api_url:
|
137
|
+
os.environ["GITARSENAL_API_URL"] = args.api_url
|
138
|
+
print(f"✅ Set GITARSENAL_API_URL from command line")
|
123
139
|
|
124
|
-
if args.
|
125
|
-
os.environ["
|
126
|
-
|
140
|
+
if args.api_key:
|
141
|
+
os.environ["GITARSENAL_API_KEY"] = args.api_key
|
142
|
+
print(f"✅ Set GITARSENAL_API_KEY from command line")
|
127
143
|
|
128
144
|
# Get tokens
|
129
145
|
token_id, token_secret = get_tokens()
|
130
|
-
# print(f"Token ID: [HIDDEN]")
|
131
|
-
# print(f"Token Secret: [HIDDEN]")
|
132
|
-
|
133
|
-
# # Check if tokens are set in environment variables
|
134
|
-
# print(f"\n🔍 DEBUG: Checking environment variables")
|
135
|
-
# print(f"🔍 MODAL_TOKEN_ID exists: {'Yes' if os.environ.get('MODAL_TOKEN_ID') else 'No'}")
|
136
|
-
# print(f"🔍 MODAL_TOKEN_SECRET exists: {'Yes' if os.environ.get('MODAL_TOKEN_SECRET') else 'No'}")
|
137
|
-
# if os.environ.get('MODAL_TOKEN_ID'):
|
138
|
-
# print(f"🔍 MODAL_TOKEN_ID length: {len(os.environ.get('MODAL_TOKEN_ID'))}")
|
139
|
-
# if os.environ.get('MODAL_TOKEN_SECRET'):
|
140
|
-
# print(f"🔍 MODAL_TOKEN_SECRET length: {len(os.environ.get('MODAL_TOKEN_SECRET'))}")
|
141
146
|
|
142
147
|
# Write the tokens to a file for use by other scripts
|
143
148
|
tokens_file = Path(__file__).parent / "modal_tokens.json"
|
@@ -19,8 +19,8 @@ try:
|
|
19
19
|
print(f"✅ Using tokens from proxy server or defaults")
|
20
20
|
except ImportError:
|
21
21
|
# If the module is not available, use hardcoded tokens
|
22
|
-
TOKEN_ID = "ak-sLhYqCjkvixiYcb9LAuCHp"
|
23
|
-
TOKEN_SECRET = "as-fPzD0Zm0dl6IFAEkhaH9pq" # Real token secret from fr8mafia profile
|
22
|
+
# TOKEN_ID = "ak-sLhYqCjkvixiYcb9LAuCHp"
|
23
|
+
# TOKEN_SECRET = "as-fPzD0Zm0dl6IFAEkhaH9pq" # Real token secret from fr8mafia profile
|
24
24
|
print(f"⚠️ Using hardcoded tokens")
|
25
25
|
|
26
26
|
# Set tokens directly in environment
|
@@ -1,77 +0,0 @@
|
|
1
|
-
# Modal Token Solution
|
2
|
-
|
3
|
-
This directory contains several scripts to solve the Modal token authentication issue. The problem occurs when Modal cannot find or validate the authentication token, resulting in errors like "Token missing" or "Could not authenticate client".
|
4
|
-
|
5
|
-
## Overview of the Solution
|
6
|
-
|
7
|
-
We've implemented a comprehensive solution that uses multiple approaches to ensure Modal can authenticate properly:
|
8
|
-
|
9
|
-
1. **fetch_modal_tokens.py**: Fetches tokens from the proxy server.
|
10
|
-
2. **modal_token_solution.py**: The main comprehensive solution that combines all approaches.
|
11
|
-
3. **modal_auth_patch.py**: A direct patch for Modal's authentication system.
|
12
|
-
4. **fix_modal_token.py**: A basic token setup script.
|
13
|
-
5. **fix_modal_token_advanced.py**: An advanced version with more approaches.
|
14
|
-
|
15
|
-
## How It Works
|
16
|
-
|
17
|
-
Our solution uses multiple approaches to ensure Modal authentication works:
|
18
|
-
|
19
|
-
1. **Token Fetching**: Tries to fetch tokens from the proxy server.
|
20
|
-
2. **Environment Variables**: Sets `MODAL_TOKEN_ID` and `MODAL_TOKEN_SECRET` environment variables.
|
21
|
-
3. **Token Files**: Creates token files in various formats and locations that Modal might look for.
|
22
|
-
4. **Modal CLI**: Attempts to use the Modal CLI to set the token with the correct profile.
|
23
|
-
5. **Direct Patching**: Directly patches Modal's authentication system to always return our tokens.
|
24
|
-
6. **Monkey Patching**: Monkey-patches Modal's import system to inject our tokens.
|
25
|
-
7. **Authentication Testing**: Tests that the authentication works by creating a simple Modal app.
|
26
|
-
|
27
|
-
## Usage
|
28
|
-
|
29
|
-
The scripts are used in this order of preference:
|
30
|
-
|
31
|
-
1. First, try `modal_token_solution.py` (most comprehensive)
|
32
|
-
2. If that fails, fall back to `modal_auth_patch.py`
|
33
|
-
3. If that fails, fall back to `fix_modal_token.py`
|
34
|
-
|
35
|
-
In most cases, you should simply import `modal_token_solution` before importing Modal:
|
36
|
-
|
37
|
-
```python
|
38
|
-
import modal_token_solution
|
39
|
-
import modal
|
40
|
-
|
41
|
-
# Now Modal will use our tokens
|
42
|
-
```
|
43
|
-
|
44
|
-
## Proxy Server Integration
|
45
|
-
|
46
|
-
The solution now integrates with the proxy server to fetch tokens:
|
47
|
-
|
48
|
-
1. **fetch_modal_tokens.py**: This script fetches tokens from the proxy server using the `MODAL_PROXY_URL` and `MODAL_PROXY_API_KEY` environment variables.
|
49
|
-
2. If the proxy server is not available, it falls back to hardcoded tokens.
|
50
|
-
3. All other scripts try to use the fetch_modal_tokens module first before falling back to hardcoded tokens.
|
51
|
-
|
52
|
-
## Troubleshooting
|
53
|
-
|
54
|
-
If you still encounter token issues:
|
55
|
-
|
56
|
-
1. Check that the tokens are correct (token ID: `ak-sLhYqCjkvixiYcb9LAuCHp`, token secret: `as-fPzD0Zm0dl6IFAEkhaH9pq`).
|
57
|
-
2. Verify that the token files are created in the correct locations:
|
58
|
-
- `~/.modal/token.json`
|
59
|
-
- `~/.modalconfig`
|
60
|
-
3. Check if the proxy server is accessible and returning valid tokens.
|
61
|
-
4. Try running the scripts manually to see detailed output.
|
62
|
-
|
63
|
-
## Implementation Details
|
64
|
-
|
65
|
-
- **Token Values**: We try to fetch tokens from the proxy server, with fallback to hardcoded values.
|
66
|
-
- **File Locations**: Token files are created in the user's home directory under `~/.modal/`.
|
67
|
-
- **Patching**: We use Python's dynamic nature to patch Modal's authentication system at runtime.
|
68
|
-
- **Profile**: We use the `fr8mafia` profile when setting tokens via the CLI.
|
69
|
-
|
70
|
-
## Files
|
71
|
-
|
72
|
-
- **fetch_modal_tokens.py**: Fetches tokens from the proxy server.
|
73
|
-
- **modal_token_solution.py**: Comprehensive solution combining all approaches.
|
74
|
-
- **modal_auth_patch.py**: Direct patch for Modal's authentication system.
|
75
|
-
- **fix_modal_token.py**: Basic token setup script.
|
76
|
-
- **fix_modal_token_advanced.py**: Advanced version with more approaches.
|
77
|
-
- **test_modal_auth.py**: Test script for Modal authentication.
|
@@ -1,82 +0,0 @@
|
|
1
|
-
# Modal Token Setup Solution
|
2
|
-
|
3
|
-
This document explains how the Modal token setup solution works in GitArsenal CLI.
|
4
|
-
|
5
|
-
## Problem
|
6
|
-
|
7
|
-
The GitArsenal CLI was failing with errors like:
|
8
|
-
|
9
|
-
```
|
10
|
-
🔍 MODAL_TOKEN_ID not found in environment.
|
11
|
-
❌ No Modal token found in environment variables
|
12
|
-
❌ Modal token file not found
|
13
|
-
❌ Could not find Modal token in any location
|
14
|
-
```
|
15
|
-
|
16
|
-
This happened because the Modal token was not being properly set in the environment variables.
|
17
|
-
|
18
|
-
## Solution
|
19
|
-
|
20
|
-
We implemented a comprehensive solution to automatically find and set up the Modal token from various sources:
|
21
|
-
|
22
|
-
1. Created a `setup_modal_token.py` module that:
|
23
|
-
- Checks for the token in environment variables (MODAL_TOKEN_ID and MODAL_TOKEN)
|
24
|
-
- Checks for the token in GitArsenal credentials file (~/.gitarsenal/credentials.json)
|
25
|
-
- Checks for the token in Modal token file (~/.modal/token.json)
|
26
|
-
- Sets the token in both MODAL_TOKEN_ID and MODAL_TOKEN environment variables
|
27
|
-
|
28
|
-
2. Modified key files to use this module:
|
29
|
-
- `gitarsenal.py` - Main CLI entry point
|
30
|
-
- `modal_proxy_service.py` - Modal proxy service
|
31
|
-
- `test_modalSandboxScript.py` - Modal sandbox script
|
32
|
-
|
33
|
-
3. Created a wrapper script `run_with_modal_token.py` that:
|
34
|
-
- Sets up the Modal token using the setup_modal_token module
|
35
|
-
- Runs a specified command with the token properly set in the environment
|
36
|
-
|
37
|
-
## Usage
|
38
|
-
|
39
|
-
### Running Commands with Modal Token
|
40
|
-
|
41
|
-
Use the wrapper script to run any command that requires Modal authentication:
|
42
|
-
|
43
|
-
```bash
|
44
|
-
python run_with_modal_token.py <command> [args...]
|
45
|
-
```
|
46
|
-
|
47
|
-
Example:
|
48
|
-
|
49
|
-
```bash
|
50
|
-
python run_with_modal_token.py python modal_proxy_service.py
|
51
|
-
```
|
52
|
-
|
53
|
-
### Setting Up Modal Token
|
54
|
-
|
55
|
-
If you need to set up the Modal token manually:
|
56
|
-
|
57
|
-
```bash
|
58
|
-
python setup_modal_token.py
|
59
|
-
```
|
60
|
-
|
61
|
-
This will prompt you for the token if it's not found in any of the sources.
|
62
|
-
|
63
|
-
### Adding Modal Token to GitArsenal Credentials
|
64
|
-
|
65
|
-
You can also add the Modal token to GitArsenal credentials:
|
66
|
-
|
67
|
-
```bash
|
68
|
-
./gitarsenal.py credentials set modal_token
|
69
|
-
```
|
70
|
-
|
71
|
-
## How It Works
|
72
|
-
|
73
|
-
1. The `setup_modal_token.py` module checks multiple sources for the Modal token:
|
74
|
-
- Environment variables (MODAL_TOKEN_ID and MODAL_TOKEN)
|
75
|
-
- GitArsenal credentials file (~/.gitarsenal/credentials.json)
|
76
|
-
- Modal token file (~/.modal/token.json)
|
77
|
-
|
78
|
-
2. When it finds a token, it sets both MODAL_TOKEN_ID and MODAL_TOKEN environment variables.
|
79
|
-
|
80
|
-
3. The modified files import and use this module to ensure the token is set before any Modal operations.
|
81
|
-
|
82
|
-
4. The wrapper script makes it easy to run any command with the token properly set up.
|