prismor 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl
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.
- prismor/__init__.py +1 -1
- prismor/api.py +87 -8
- prismor/cli.py +150 -44
- {prismor-0.1.0.dist-info → prismor-0.1.1.dist-info}/METADATA +1 -1
- prismor-0.1.1.dist-info/RECORD +9 -0
- prismor-0.1.0.dist-info/RECORD +0 -9
- {prismor-0.1.0.dist-info → prismor-0.1.1.dist-info}/WHEEL +0 -0
- {prismor-0.1.0.dist-info → prismor-0.1.1.dist-info}/entry_points.txt +0 -0
- {prismor-0.1.0.dist-info → prismor-0.1.1.dist-info}/licenses/LICENSE +0 -0
- {prismor-0.1.0.dist-info → prismor-0.1.1.dist-info}/top_level.txt +0 -0
prismor/__init__.py
CHANGED
prismor/api.py
CHANGED
|
@@ -26,12 +26,52 @@ class PrismorClient:
|
|
|
26
26
|
"Please set it with: export PRISMOR_API_KEY=your_api_key"
|
|
27
27
|
)
|
|
28
28
|
|
|
29
|
-
self.base_url = "
|
|
29
|
+
# self.base_url = "http://localhost:3000"
|
|
30
|
+
self.base_url = "https://prismor.dev"
|
|
30
31
|
self.headers = {
|
|
31
32
|
"Authorization": f"Bearer {self.api_key}",
|
|
32
33
|
"Content-Type": "application/json"
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
def authenticate(self) -> Dict[str, Any]:
|
|
37
|
+
"""Authenticate with the Prismor API using the API key.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Dictionary containing user information and repositories
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
PrismorAPIError: If authentication fails
|
|
44
|
+
"""
|
|
45
|
+
try:
|
|
46
|
+
response = requests.post(
|
|
47
|
+
f"{self.base_url}/api/cli/auth",
|
|
48
|
+
json={"apiKey": self.api_key},
|
|
49
|
+
headers={"Content-Type": "application/json"},
|
|
50
|
+
timeout=30
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if response.status_code == 401:
|
|
54
|
+
raise PrismorAPIError("Invalid API key. Please check your PRISMOR_API_KEY.")
|
|
55
|
+
|
|
56
|
+
if response.status_code == 400:
|
|
57
|
+
raise PrismorAPIError("API key is required.")
|
|
58
|
+
|
|
59
|
+
if response.status_code >= 400:
|
|
60
|
+
error_msg = response.json().get("error", "Authentication failed")
|
|
61
|
+
raise PrismorAPIError(f"Authentication error: {error_msg}")
|
|
62
|
+
|
|
63
|
+
response.raise_for_status()
|
|
64
|
+
return response.json()
|
|
65
|
+
|
|
66
|
+
except requests.exceptions.Timeout:
|
|
67
|
+
raise PrismorAPIError("Authentication request timed out.")
|
|
68
|
+
except requests.exceptions.ConnectionError:
|
|
69
|
+
raise PrismorAPIError(
|
|
70
|
+
"Failed to connect to Prismor API. Please check your internet connection."
|
|
71
|
+
)
|
|
72
|
+
except requests.exceptions.RequestException as e:
|
|
73
|
+
raise PrismorAPIError(f"Authentication request failed: {str(e)}")
|
|
74
|
+
|
|
35
75
|
def normalize_repo_url(self, repo: str) -> str:
|
|
36
76
|
"""Normalize repository input to a full GitHub URL.
|
|
37
77
|
|
|
@@ -59,7 +99,8 @@ class PrismorClient:
|
|
|
59
99
|
vex: bool = False,
|
|
60
100
|
sbom: bool = False,
|
|
61
101
|
detect_secret: bool = False,
|
|
62
|
-
fullscan: bool = False
|
|
102
|
+
fullscan: bool = False,
|
|
103
|
+
branch: Optional[str] = None
|
|
63
104
|
) -> Dict[str, Any]:
|
|
64
105
|
"""Perform security scan on a GitHub repository.
|
|
65
106
|
|
|
@@ -69,41 +110,59 @@ class PrismorClient:
|
|
|
69
110
|
sbom: Enable SBOM generation
|
|
70
111
|
detect_secret: Enable secret detection
|
|
71
112
|
fullscan: Enable all scan types
|
|
113
|
+
branch: Specific branch to scan (defaults to main/master)
|
|
72
114
|
|
|
73
115
|
Returns:
|
|
74
116
|
Dictionary containing scan results
|
|
75
117
|
"""
|
|
76
118
|
repo_url = self.normalize_repo_url(repo)
|
|
77
119
|
|
|
78
|
-
#
|
|
120
|
+
# First authenticate to get user info
|
|
121
|
+
auth_response = self.authenticate()
|
|
122
|
+
user_info = auth_response.get("user", {})
|
|
123
|
+
|
|
124
|
+
# Prepare request payload for CLI scan
|
|
79
125
|
payload = {
|
|
80
126
|
"repo_url": repo_url,
|
|
127
|
+
"api_key": self.api_key,
|
|
81
128
|
"vex": vex or fullscan,
|
|
82
129
|
"sbom": sbom or fullscan,
|
|
83
130
|
"detect_secret": detect_secret or fullscan,
|
|
84
|
-
"fullscan": fullscan
|
|
131
|
+
"fullscan": fullscan,
|
|
132
|
+
"branch": branch
|
|
85
133
|
}
|
|
86
134
|
|
|
87
135
|
try:
|
|
88
136
|
response = requests.post(
|
|
89
|
-
f"{self.base_url}/scan",
|
|
137
|
+
f"{self.base_url}/api/cli/scan",
|
|
90
138
|
json=payload,
|
|
91
|
-
headers=
|
|
139
|
+
headers={"Content-Type": "application/json"},
|
|
92
140
|
timeout=300 # 5 minute timeout
|
|
93
141
|
)
|
|
94
142
|
|
|
95
143
|
if response.status_code == 401:
|
|
144
|
+
error_data = response.json()
|
|
145
|
+
if error_data.get("action") == "integrate_github":
|
|
146
|
+
raise PrismorAPIError(
|
|
147
|
+
f"{error_data.get('message', 'GitHub integration required')}\n"
|
|
148
|
+
f"Please visit: {error_data.get('integration_url', 'https://prismor.dev/dashboard')}"
|
|
149
|
+
)
|
|
96
150
|
raise PrismorAPIError("Invalid API key. Please check your PRISMOR_API_KEY.")
|
|
97
151
|
|
|
98
152
|
if response.status_code == 404:
|
|
99
|
-
raise PrismorAPIError("
|
|
153
|
+
raise PrismorAPIError("CLI scan endpoint not found. Please check if CLI endpoints are available.")
|
|
100
154
|
|
|
101
155
|
if response.status_code >= 400:
|
|
102
156
|
error_msg = response.json().get("error", "Unknown error")
|
|
103
157
|
raise PrismorAPIError(f"API error: {error_msg}")
|
|
104
158
|
|
|
105
159
|
response.raise_for_status()
|
|
106
|
-
|
|
160
|
+
result = response.json()
|
|
161
|
+
|
|
162
|
+
# Handle the new response format from CLI endpoint
|
|
163
|
+
if result.get("ok") and "results" in result:
|
|
164
|
+
return result["results"]
|
|
165
|
+
return result
|
|
107
166
|
|
|
108
167
|
except requests.exceptions.Timeout:
|
|
109
168
|
raise PrismorAPIError(
|
|
@@ -115,4 +174,24 @@ class PrismorClient:
|
|
|
115
174
|
)
|
|
116
175
|
except requests.exceptions.RequestException as e:
|
|
117
176
|
raise PrismorAPIError(f"Request failed: {str(e)}")
|
|
177
|
+
|
|
178
|
+
def get_repositories(self) -> Dict[str, Any]:
|
|
179
|
+
"""Get user's repositories.
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
Dictionary containing user repositories
|
|
183
|
+
|
|
184
|
+
Raises:
|
|
185
|
+
PrismorAPIError: If request fails
|
|
186
|
+
"""
|
|
187
|
+
auth_response = self.authenticate()
|
|
188
|
+
user_info = auth_response.get("user", {})
|
|
189
|
+
return {
|
|
190
|
+
"repositories": user_info.get("repositories", []),
|
|
191
|
+
"user": {
|
|
192
|
+
"id": user_info.get("id"),
|
|
193
|
+
"email": user_info.get("email"),
|
|
194
|
+
"name": user_info.get("name")
|
|
195
|
+
}
|
|
196
|
+
}
|
|
118
197
|
|
prismor/cli.py
CHANGED
|
@@ -38,56 +38,79 @@ def format_scan_results(results: dict, scan_type: str):
|
|
|
38
38
|
click.secho("Repository:", fg="yellow", bold=True)
|
|
39
39
|
click.echo(f" {results['repository']}\n")
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
click.secho(f"Status: ", fg="yellow", bold=True, nl=False)
|
|
45
|
-
click.secho(results["status"], fg=status_color)
|
|
46
|
-
click.echo()
|
|
41
|
+
if "branch" in results:
|
|
42
|
+
click.secho("Branch:", fg="yellow", bold=True)
|
|
43
|
+
click.echo(f" {results['branch']}\n")
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
if "commit_sha" in results:
|
|
46
|
+
click.secho("Commit SHA:", fg="yellow", bold=True)
|
|
47
|
+
click.echo(f" {results['commit_sha']}\n")
|
|
48
|
+
|
|
49
|
+
# Display scan results for each scan type
|
|
50
|
+
if "scans" in results:
|
|
51
|
+
scans = results["scans"]
|
|
51
52
|
|
|
52
53
|
# Vulnerability scan results
|
|
53
|
-
if "
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
if "vulnerability" in scans:
|
|
55
|
+
vuln_scan = scans["vulnerability"]
|
|
56
|
+
click.secho("Vulnerability Scan:", fg="yellow", bold=True)
|
|
57
|
+
status_color = "green" if vuln_scan.get("status") == "success" else "red"
|
|
58
|
+
click.secho(f" Status: {vuln_scan.get('status', 'unknown')}", fg=status_color)
|
|
59
|
+
|
|
60
|
+
if "scan_results" in vuln_scan:
|
|
61
|
+
scan_data = vuln_scan["scan_results"]
|
|
62
|
+
if "vulnerabilities" in scan_data or "Results" in scan_data:
|
|
63
|
+
vuln_data = scan_data.get("vulnerabilities", scan_data.get("Results", []))
|
|
64
|
+
if isinstance(vuln_data, list):
|
|
65
|
+
click.echo(f" Vulnerabilities Found: {len(vuln_data)}")
|
|
66
|
+
else:
|
|
67
|
+
click.echo(f" Vulnerabilities: Data available")
|
|
68
|
+
|
|
69
|
+
if "public_url" in vuln_scan:
|
|
70
|
+
click.echo(f" Results URL: {vuln_scan['public_url']}")
|
|
60
71
|
click.echo()
|
|
61
72
|
|
|
62
|
-
#
|
|
63
|
-
if "
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
# SBOM results
|
|
74
|
+
if "sbom" in scans:
|
|
75
|
+
sbom_scan = scans["sbom"]
|
|
76
|
+
click.secho("SBOM Generation:", fg="yellow", bold=True)
|
|
77
|
+
status_color = "green" if sbom_scan.get("status") == "success" else "red"
|
|
78
|
+
click.secho(f" Status: {sbom_scan.get('status', 'unknown')}", fg=status_color)
|
|
79
|
+
|
|
80
|
+
if "sbom" in sbom_scan:
|
|
81
|
+
sbom_data = sbom_scan["sbom"]
|
|
82
|
+
if isinstance(sbom_data, list):
|
|
83
|
+
click.echo(f" Artifacts Found: {len(sbom_data)}")
|
|
84
|
+
else:
|
|
85
|
+
click.echo(f" SBOM: Data available")
|
|
86
|
+
|
|
87
|
+
if "public_url" in sbom_scan:
|
|
88
|
+
click.echo(f" Results URL: {sbom_scan['public_url']}")
|
|
71
89
|
click.echo()
|
|
72
90
|
|
|
73
|
-
#
|
|
74
|
-
if "
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
91
|
+
# Secret scan results
|
|
92
|
+
if "secret" in scans:
|
|
93
|
+
secret_scan = scans["secret"]
|
|
94
|
+
click.secho("Secret Detection:", fg="yellow", bold=True)
|
|
95
|
+
status_color = "green" if secret_scan.get("status") == "success" else "red"
|
|
96
|
+
click.secho(f" Status: {secret_scan.get('status', 'unknown')}", fg=status_color)
|
|
97
|
+
|
|
98
|
+
if "summary" in secret_scan:
|
|
99
|
+
summary = secret_scan["summary"]
|
|
100
|
+
if isinstance(summary, dict):
|
|
101
|
+
for key, value in summary.items():
|
|
102
|
+
click.echo(f" {key}: {value}")
|
|
103
|
+
else:
|
|
104
|
+
click.echo(f" Summary: {summary}")
|
|
105
|
+
|
|
106
|
+
if "public_url" in secret_scan:
|
|
107
|
+
click.echo(f" Results URL: {secret_scan['public_url']}")
|
|
81
108
|
click.echo()
|
|
82
109
|
|
|
83
|
-
# Display
|
|
84
|
-
if "
|
|
85
|
-
click.secho("
|
|
86
|
-
click.echo(f" {results['
|
|
87
|
-
|
|
88
|
-
if "presigned_url" in results:
|
|
89
|
-
click.secho("Download URL:", fg="yellow", bold=True)
|
|
90
|
-
click.echo(f" {results['presigned_url']}\n")
|
|
110
|
+
# Display scan timestamp
|
|
111
|
+
if "scanned_at" in results:
|
|
112
|
+
click.secho("Scanned At:", fg="yellow", bold=True)
|
|
113
|
+
click.echo(f" {results['scanned_at']}\n")
|
|
91
114
|
|
|
92
115
|
click.echo("=" * 60 + "\n")
|
|
93
116
|
|
|
@@ -102,17 +125,21 @@ def format_scan_results(results: dict, scan_type: str):
|
|
|
102
125
|
@click.option("--sbom", is_flag=True, help="Generate Software Bill of Materials")
|
|
103
126
|
@click.option("--detect-secret", is_flag=True, help="Detect secrets in repository")
|
|
104
127
|
@click.option("--fullscan", is_flag=True, help="Perform all scan types")
|
|
128
|
+
@click.option("--branch", type=str, help="Specific branch to scan (defaults to main/master)")
|
|
105
129
|
@click.option("--json", "output_json", is_flag=True, help="Output results in JSON format")
|
|
106
130
|
@click.version_option(version="0.1.0", prog_name="prismor")
|
|
107
131
|
@click.pass_context
|
|
108
132
|
def cli(ctx, scan: Optional[str], vex: bool, sbom: bool, detect_secret: bool,
|
|
109
|
-
fullscan: bool, output_json: bool):
|
|
133
|
+
fullscan: bool, branch: Optional[str], output_json: bool):
|
|
110
134
|
"""Prismor CLI - Security scanning tool for GitHub repositories.
|
|
111
135
|
|
|
112
136
|
Examples:
|
|
113
137
|
prismor --scan username/repo --vex
|
|
114
138
|
prismor --scan username/repo --fullscan
|
|
115
139
|
prismor --scan https://github.com/username/repo --detect-secret
|
|
140
|
+
prismor --scan username/repo --sbom --branch develop
|
|
141
|
+
prismor status
|
|
142
|
+
prismor repos
|
|
116
143
|
"""
|
|
117
144
|
# If no command and no scan option, show help
|
|
118
145
|
if ctx.invoked_subcommand is None and not scan:
|
|
@@ -152,7 +179,8 @@ def cli(ctx, scan: Optional[str], vex: bool, sbom: bool, detect_secret: bool,
|
|
|
152
179
|
vex=vex,
|
|
153
180
|
sbom=sbom,
|
|
154
181
|
detect_secret=detect_secret,
|
|
155
|
-
fullscan=fullscan
|
|
182
|
+
fullscan=fullscan,
|
|
183
|
+
branch=branch
|
|
156
184
|
)
|
|
157
185
|
|
|
158
186
|
# Output results
|
|
@@ -196,10 +224,88 @@ def config():
|
|
|
196
224
|
click.echo("\nTo set your API key, run:")
|
|
197
225
|
click.echo(" export PRISMOR_API_KEY=your_api_key")
|
|
198
226
|
|
|
199
|
-
click.echo("\nAPI Endpoint:
|
|
227
|
+
# click.echo("\nAPI Endpoint: http://localhost:3000")
|
|
200
228
|
click.echo("=" * 60 + "\n")
|
|
201
229
|
|
|
202
230
|
|
|
231
|
+
@cli.command()
|
|
232
|
+
def repos():
|
|
233
|
+
"""List your connected repositories."""
|
|
234
|
+
try:
|
|
235
|
+
client = PrismorClient()
|
|
236
|
+
repos_data = client.get_repositories()
|
|
237
|
+
|
|
238
|
+
click.echo("\n" + "=" * 60)
|
|
239
|
+
click.secho(" Your Repositories", fg="cyan", bold=True)
|
|
240
|
+
click.echo("=" * 60 + "\n")
|
|
241
|
+
|
|
242
|
+
user_info = repos_data.get("user", {})
|
|
243
|
+
if user_info:
|
|
244
|
+
click.secho(f"User: {user_info.get('name', 'Unknown')} ({user_info.get('email', 'No email')})", fg="yellow")
|
|
245
|
+
click.echo()
|
|
246
|
+
|
|
247
|
+
repositories = repos_data.get("repositories", [])
|
|
248
|
+
if repositories:
|
|
249
|
+
for repo in repositories:
|
|
250
|
+
click.secho(f"• {repo.get('name', 'Unknown')}", fg="green")
|
|
251
|
+
click.echo(f" URL: {repo.get('htmlUrl', 'No URL')}")
|
|
252
|
+
click.echo(f" Owner: {repo.get('githubOwner', 'Unknown')}")
|
|
253
|
+
click.echo()
|
|
254
|
+
else:
|
|
255
|
+
print_warning("No repositories found. Connect repositories through the web interface.")
|
|
256
|
+
|
|
257
|
+
click.echo("=" * 60 + "\n")
|
|
258
|
+
|
|
259
|
+
except PrismorAPIError as e:
|
|
260
|
+
print_error(str(e))
|
|
261
|
+
sys.exit(1)
|
|
262
|
+
except Exception as e:
|
|
263
|
+
print_error(f"Unexpected error: {str(e)}")
|
|
264
|
+
sys.exit(1)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
@cli.command()
|
|
268
|
+
def status():
|
|
269
|
+
"""Check your account status and GitHub integration."""
|
|
270
|
+
try:
|
|
271
|
+
client = PrismorClient()
|
|
272
|
+
auth_data = client.authenticate()
|
|
273
|
+
|
|
274
|
+
click.echo("\n" + "=" * 60)
|
|
275
|
+
click.secho(" Account Status", fg="cyan", bold=True)
|
|
276
|
+
click.echo("=" * 60 + "\n")
|
|
277
|
+
|
|
278
|
+
user_info = auth_data.get("user", {})
|
|
279
|
+
if user_info:
|
|
280
|
+
click.secho(f"User: {user_info.get('name', 'Unknown')} ({user_info.get('email', 'No email')})", fg="yellow")
|
|
281
|
+
click.echo()
|
|
282
|
+
|
|
283
|
+
repositories = user_info.get("repositories", [])
|
|
284
|
+
click.secho(f"Connected Repositories: {len(repositories)}", fg="green")
|
|
285
|
+
|
|
286
|
+
if repositories:
|
|
287
|
+
click.echo("\nRepository List:")
|
|
288
|
+
for repo in repositories:
|
|
289
|
+
click.echo(f" • {repo.get('name', 'Unknown')} ({repo.get('htmlUrl', 'No URL')})")
|
|
290
|
+
else:
|
|
291
|
+
print_warning("No repositories connected.")
|
|
292
|
+
click.echo("\nTo connect repositories:")
|
|
293
|
+
click.echo(" 1. Visit https://prismor.dev/dashboard")
|
|
294
|
+
click.echo(" 2. Connect your GitHub account")
|
|
295
|
+
click.echo(" 3. Select repositories to scan")
|
|
296
|
+
else:
|
|
297
|
+
print_error("Failed to retrieve account information.")
|
|
298
|
+
|
|
299
|
+
click.echo("\n" + "=" * 60 + "\n")
|
|
300
|
+
|
|
301
|
+
except PrismorAPIError as e:
|
|
302
|
+
print_error(str(e))
|
|
303
|
+
sys.exit(1)
|
|
304
|
+
except Exception as e:
|
|
305
|
+
print_error(f"Unexpected error: {str(e)}")
|
|
306
|
+
sys.exit(1)
|
|
307
|
+
|
|
308
|
+
|
|
203
309
|
def main():
|
|
204
310
|
"""Entry point for the CLI."""
|
|
205
311
|
cli()
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
prismor/__init__.py,sha256=Wz9TJXpg-R4rq3KkawmGdozbNPeLMl2L8dTaAJKgBZQ,230
|
|
2
|
+
prismor/api.py,sha256=Sx9YahTwGfO0cWXkVbjE0w_1hSrrhMYWzQw4tWxitQM,7149
|
|
3
|
+
prismor/cli.py,sha256=a5DZ-x3g-L7-6R4-uJXlP_-V-n0Rubh2C_7EMvWtV2A,11452
|
|
4
|
+
prismor-0.1.1.dist-info/licenses/LICENSE,sha256=qWFF8Eh6gpZOq_3effdd6hfeMN2WN9ZG4vOyFk2MyhU,1065
|
|
5
|
+
prismor-0.1.1.dist-info/METADATA,sha256=RVjWQzwXVGUbUEVzKk9ilXzJowLFVe1o1nKqCmBA-Zk,9394
|
|
6
|
+
prismor-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
prismor-0.1.1.dist-info/entry_points.txt,sha256=Uiu0HW04eq2Gb6sQC9o-LqMKMyW1SKwkojxrkFeVfqg,45
|
|
8
|
+
prismor-0.1.1.dist-info/top_level.txt,sha256=nlJGoJ3fQXRL27RXQ5LJU2LX1kl1VSgKXyKjcSR28lw,8
|
|
9
|
+
prismor-0.1.1.dist-info/RECORD,,
|
prismor-0.1.0.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
prismor/__init__.py,sha256=d_7a1UaXHGT7kAzI5fERetpR2vEj349becGSTKatQU0,230
|
|
2
|
-
prismor/api.py,sha256=jnbxgzDJjYLGxC5viT18xVjcmbupFecvlb-ph8J0yik,3938
|
|
3
|
-
prismor/cli.py,sha256=zjRJH9li_0_2CNquI4Y14alGpmiq1d-P_rZBTp4bS6I,7310
|
|
4
|
-
prismor-0.1.0.dist-info/licenses/LICENSE,sha256=qWFF8Eh6gpZOq_3effdd6hfeMN2WN9ZG4vOyFk2MyhU,1065
|
|
5
|
-
prismor-0.1.0.dist-info/METADATA,sha256=2boiqdtLo65Do3pxw_P7wWmU-FjVv95S43b3xfNT7Ps,9394
|
|
6
|
-
prismor-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
-
prismor-0.1.0.dist-info/entry_points.txt,sha256=Uiu0HW04eq2Gb6sQC9o-LqMKMyW1SKwkojxrkFeVfqg,45
|
|
8
|
-
prismor-0.1.0.dist-info/top_level.txt,sha256=nlJGoJ3fQXRL27RXQ5LJU2LX1kl1VSgKXyKjcSR28lw,8
|
|
9
|
-
prismor-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|