stackport 0.1.5__tar.gz → 0.1.7__tar.gz

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.
Files changed (81) hide show
  1. {stackport-0.1.5/stackport.egg-info → stackport-0.1.7}/PKG-INFO +1 -1
  2. {stackport-0.1.5 → stackport-0.1.7}/backend/routes/resources.py +36 -4
  3. {stackport-0.1.5 → stackport-0.1.7}/backend/routes/stats.py +15 -2
  4. {stackport-0.1.5 → stackport-0.1.7}/pyproject.toml +1 -1
  5. {stackport-0.1.5 → stackport-0.1.7/stackport.egg-info}/PKG-INFO +1 -1
  6. stackport-0.1.7/stackport.egg-info/SOURCES.txt +114 -0
  7. {stackport-0.1.5 → stackport-0.1.7}/tests/test_routes.py +6 -0
  8. stackport-0.1.7/ui/dist/assets/index-DI-V3ZCb.js +527 -0
  9. stackport-0.1.7/ui/dist/assets/index-DM3oKaVN.css +1 -0
  10. stackport-0.1.7/ui/dist/aws-icons/acm.svg +18 -0
  11. stackport-0.1.7/ui/dist/aws-icons/apigateway.svg +18 -0
  12. stackport-0.1.7/ui/dist/aws-icons/appsync.svg +20 -0
  13. stackport-0.1.7/ui/dist/aws-icons/athena.svg +18 -0
  14. stackport-0.1.7/ui/dist/aws-icons/cloudformation.svg +18 -0
  15. stackport-0.1.7/ui/dist/aws-icons/cloudfront.svg +18 -0
  16. stackport-0.1.7/ui/dist/aws-icons/cognito-idp.svg +18 -0
  17. stackport-0.1.7/ui/dist/aws-icons/dynamodb.svg +18 -0
  18. stackport-0.1.7/ui/dist/aws-icons/ec2.svg +18 -0
  19. stackport-0.1.7/ui/dist/aws-icons/ecr.svg +20 -0
  20. stackport-0.1.7/ui/dist/aws-icons/ecs.svg +20 -0
  21. stackport-0.1.7/ui/dist/aws-icons/elasticache.svg +18 -0
  22. stackport-0.1.7/ui/dist/aws-icons/elasticfilesystem.svg +18 -0
  23. stackport-0.1.7/ui/dist/aws-icons/elasticloadbalancing.svg +18 -0
  24. stackport-0.1.7/ui/dist/aws-icons/elasticmapreduce.svg +18 -0
  25. stackport-0.1.7/ui/dist/aws-icons/events.svg +18 -0
  26. stackport-0.1.7/ui/dist/aws-icons/firehose.svg +20 -0
  27. stackport-0.1.7/ui/dist/aws-icons/glue.svg +18 -0
  28. stackport-0.1.7/ui/dist/aws-icons/iam.svg +18 -0
  29. stackport-0.1.7/ui/dist/aws-icons/kinesis.svg +18 -0
  30. stackport-0.1.7/ui/dist/aws-icons/kms.svg +18 -0
  31. stackport-0.1.7/ui/dist/aws-icons/lambda.svg +18 -0
  32. stackport-0.1.7/ui/dist/aws-icons/logs.svg +18 -0
  33. stackport-0.1.7/ui/dist/aws-icons/monitoring.svg +18 -0
  34. stackport-0.1.7/ui/dist/aws-icons/rds.svg +18 -0
  35. stackport-0.1.7/ui/dist/aws-icons/route53.svg +18 -0
  36. stackport-0.1.7/ui/dist/aws-icons/s3.svg +18 -0
  37. stackport-0.1.7/ui/dist/aws-icons/secretsmanager.svg +18 -0
  38. stackport-0.1.7/ui/dist/aws-icons/ses.svg +16 -0
  39. stackport-0.1.7/ui/dist/aws-icons/sns.svg +18 -0
  40. stackport-0.1.7/ui/dist/aws-icons/sqs.svg +18 -0
  41. stackport-0.1.7/ui/dist/aws-icons/ssm.svg +18 -0
  42. stackport-0.1.7/ui/dist/aws-icons/stepfunctions.svg +18 -0
  43. stackport-0.1.7/ui/dist/aws-icons/wafv2.svg +18 -0
  44. stackport-0.1.7/ui/dist/index.html +28 -0
  45. stackport-0.1.5/stackport.egg-info/SOURCES.txt +0 -46
  46. stackport-0.1.5/ui/dist/assets/index-BFwEzJQQ.css +0 -1
  47. stackport-0.1.5/ui/dist/assets/index-DeaAXMzy.js +0 -477
  48. stackport-0.1.5/ui/dist/index.html +0 -17
  49. {stackport-0.1.5 → stackport-0.1.7}/LICENSE +0 -0
  50. {stackport-0.1.5 → stackport-0.1.7}/MANIFEST.in +0 -0
  51. {stackport-0.1.5 → stackport-0.1.7}/README.md +0 -0
  52. {stackport-0.1.5 → stackport-0.1.7}/backend/__init__.py +0 -0
  53. {stackport-0.1.5 → stackport-0.1.7}/backend/aws_client.py +0 -0
  54. {stackport-0.1.5 → stackport-0.1.7}/backend/cache.py +0 -0
  55. {stackport-0.1.5 → stackport-0.1.7}/backend/config.py +0 -0
  56. {stackport-0.1.5 → stackport-0.1.7}/backend/main.py +0 -0
  57. {stackport-0.1.5 → stackport-0.1.7}/backend/routes/__init__.py +0 -0
  58. {stackport-0.1.5 → stackport-0.1.7}/backend/routes/dynamodb.py +0 -0
  59. {stackport-0.1.5 → stackport-0.1.7}/backend/routes/ec2.py +0 -0
  60. {stackport-0.1.5 → stackport-0.1.7}/backend/routes/iam.py +0 -0
  61. {stackport-0.1.5 → stackport-0.1.7}/backend/routes/lambda_svc.py +0 -0
  62. {stackport-0.1.5 → stackport-0.1.7}/backend/routes/logs.py +0 -0
  63. {stackport-0.1.5 → stackport-0.1.7}/backend/routes/s3.py +0 -0
  64. {stackport-0.1.5 → stackport-0.1.7}/backend/routes/sqs.py +0 -0
  65. {stackport-0.1.5 → stackport-0.1.7}/setup.cfg +0 -0
  66. {stackport-0.1.5 → stackport-0.1.7}/stackport.egg-info/dependency_links.txt +0 -0
  67. {stackport-0.1.5 → stackport-0.1.7}/stackport.egg-info/entry_points.txt +0 -0
  68. {stackport-0.1.5 → stackport-0.1.7}/stackport.egg-info/requires.txt +0 -0
  69. {stackport-0.1.5 → stackport-0.1.7}/stackport.egg-info/top_level.txt +0 -0
  70. {stackport-0.1.5 → stackport-0.1.7}/tests/test_cache.py +0 -0
  71. {stackport-0.1.5 → stackport-0.1.7}/tests/test_client.py +0 -0
  72. {stackport-0.1.5 → stackport-0.1.7}/tests/test_config.py +0 -0
  73. {stackport-0.1.5 → stackport-0.1.7}/tests/test_dynamodb_routes.py +0 -0
  74. {stackport-0.1.5 → stackport-0.1.7}/tests/test_ec2_routes.py +0 -0
  75. {stackport-0.1.5 → stackport-0.1.7}/tests/test_iam_routes.py +0 -0
  76. {stackport-0.1.5 → stackport-0.1.7}/tests/test_lambda_routes.py +0 -0
  77. {stackport-0.1.5 → stackport-0.1.7}/tests/test_logs_routes.py +0 -0
  78. {stackport-0.1.5 → stackport-0.1.7}/tests/test_registries.py +0 -0
  79. {stackport-0.1.5 → stackport-0.1.7}/tests/test_sqs_routes.py +0 -0
  80. {stackport-0.1.5 → stackport-0.1.7}/ui/dist/favicon.png +0 -0
  81. {stackport-0.1.5 → stackport-0.1.7}/ui/dist/favicon.svg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stackport
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Summary: Universal AWS resource browser for local emulators
5
5
  Author: Davi Reis Vieira
6
6
  License: MIT
@@ -71,6 +71,15 @@ DESCRIBE_REGISTRY: dict[tuple[str, str], tuple[str, str, str, str | None]] = {
71
71
  ("elasticmapreduce", "clusters"): ("emr", "describe_cluster", "ClusterId", "Cluster"),
72
72
  }
73
73
 
74
+ # Override the generic _ID_FIELDS for services where the default order picks
75
+ # the wrong field (e.g. Arn before Name, or Name before Id).
76
+ _PREFERRED_ID_FIELD: dict[tuple[str, str], str] = {
77
+ ("route53", "hosted_zones"): "Id",
78
+ ("events", "rules"): "Name",
79
+ ("events", "event_buses"): "Name",
80
+ ("wafv2", "web_acls"): "Name",
81
+ }
82
+
74
83
  # Known ID field names for extracting a resource identifier from list results
75
84
  _ID_FIELDS = [
76
85
  "BucketName",
@@ -119,11 +128,13 @@ _ID_FIELDS = [
119
128
  ]
120
129
 
121
130
 
122
- def _extract_id(item) -> str:
131
+ def _extract_id(item, preferred_field: str | None = None) -> str:
123
132
  """Extract a usable ID from a list API result item."""
124
133
  if isinstance(item, str):
125
134
  return item
126
135
  if isinstance(item, dict):
136
+ if preferred_field and preferred_field in item:
137
+ return str(item[preferred_field])
127
138
  for field in _ID_FIELDS:
128
139
  if field in item:
129
140
  return str(item[field])
@@ -134,12 +145,12 @@ def _extract_id(item) -> str:
134
145
  return str(item)
135
146
 
136
147
 
137
- def _summarize_item(item) -> dict:
148
+ def _summarize_item(item, preferred_field: str | None = None) -> dict:
138
149
  """Create a summary dict from a list API result item."""
139
150
  if isinstance(item, str):
140
151
  return {"id": item}
141
152
  if isinstance(item, dict):
142
- summary = {"id": _extract_id(item)}
153
+ summary = {"id": _extract_id(item, preferred_field)}
143
154
  for key, value in item.items():
144
155
  if isinstance(value, (str, int, float, bool)) or value is None:
145
156
  summary[key] = value
@@ -171,7 +182,8 @@ def list_resources(service: str):
171
182
  # Handle nested structures (e.g., cloudfront DistributionList.Items)
172
183
  if isinstance(items, dict) and "Items" in items:
173
184
  items = items.get("Items", []) or []
174
- resources[resource_type] = [_summarize_item(item) for item in items]
185
+ preferred = _PREFERRED_ID_FIELD.get((service, resource_type))
186
+ resources[resource_type] = [_summarize_item(item, preferred) for item in items]
175
187
  except Exception:
176
188
  logger.debug("Failed to list %s/%s", service, resource_type, exc_info=True)
177
189
  resources[resource_type] = []
@@ -188,6 +200,26 @@ def get_resource_detail(service: str, res_type: str, res_id: str):
188
200
  if cached is not None:
189
201
  return cached
190
202
 
203
+ # WAFv2 get_web_acl requires Name, Scope, AND Id — resolve Id from list first
204
+ if (service, res_type) == ("wafv2", "web_acls"):
205
+ try:
206
+ client = get_client("wafv2")
207
+ acls = client.list_web_acls(Scope="REGIONAL").get("WebACLs", [])
208
+ match = next((a for a in acls if a.get("Name") == res_id), None)
209
+ if not match:
210
+ raise HTTPException(404, f"Web ACL '{res_id}' not found")
211
+ resp = client.get_web_acl(Name=res_id, Scope="REGIONAL", Id=match["Id"])
212
+ resp.pop("ResponseMetadata", None)
213
+ detail = _serialize(resp.get("WebACL", resp))
214
+ result = {"service": service, "type": res_type, "id": res_id, "detail": detail}
215
+ cache.set(cache_key, result, ttl=5)
216
+ return result
217
+ except HTTPException:
218
+ raise
219
+ except Exception as exc:
220
+ logger.warning("Failed to get detail for %s/%s/%s", service, res_type, res_id, exc_info=True)
221
+ raise HTTPException(status_code=500, detail=str(exc)) from exc
222
+
191
223
  lookup = DESCRIBE_REGISTRY.get((service, res_type))
192
224
  if not lookup:
193
225
  raise HTTPException(
@@ -1,3 +1,4 @@
1
+ import importlib.metadata
1
2
  import logging
2
3
  import time
3
4
  from concurrent.futures import ThreadPoolExecutor, as_completed
@@ -8,7 +9,7 @@ from backend.aws_client import get_client
8
9
 
9
10
  logger = logging.getLogger(__name__)
10
11
  from backend.cache import cache
11
- from backend.config import STACKPORT_SERVICES
12
+ from backend.config import AWS_ENDPOINT_URL, AWS_REGION, STACKPORT_SERVICES
12
13
 
13
14
  router = APIRouter()
14
15
 
@@ -83,7 +84,19 @@ _start_time = time.time()
83
84
 
84
85
  @router.get("/health")
85
86
  def health():
86
- return {"status": "ok", "uptime_seconds": round(time.time() - _start_time, 1)}
87
+ try:
88
+ version = importlib.metadata.version("stackport")
89
+ except importlib.metadata.PackageNotFoundError:
90
+ version = "dev"
91
+ enabled = [s.strip() for s in STACKPORT_SERVICES.split(",") if s.strip()]
92
+ return {
93
+ "status": "ok",
94
+ "version": version,
95
+ "uptime_seconds": round(time.time() - _start_time, 1),
96
+ "endpoint_url": AWS_ENDPOINT_URL,
97
+ "region": AWS_REGION,
98
+ "services_count": len(enabled),
99
+ }
87
100
 
88
101
 
89
102
  # Some APIs require extra parameters to call
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "stackport"
3
- version = "0.1.5"
3
+ version = "0.1.7"
4
4
  description = "Universal AWS resource browser for local emulators"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stackport
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Summary: Universal AWS resource browser for local emulators
5
5
  Author: Davi Reis Vieira
6
6
  License: MIT
@@ -0,0 +1,114 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ backend/__init__.py
6
+ backend/aws_client.py
7
+ backend/cache.py
8
+ backend/config.py
9
+ backend/main.py
10
+ backend/../ui/dist/favicon.png
11
+ backend/../ui/dist/favicon.svg
12
+ backend/../ui/dist/index.html
13
+ backend/../ui/dist/assets/index-DI-V3ZCb.js
14
+ backend/../ui/dist/assets/index-DM3oKaVN.css
15
+ backend/../ui/dist/aws-icons/acm.svg
16
+ backend/../ui/dist/aws-icons/apigateway.svg
17
+ backend/../ui/dist/aws-icons/appsync.svg
18
+ backend/../ui/dist/aws-icons/athena.svg
19
+ backend/../ui/dist/aws-icons/cloudformation.svg
20
+ backend/../ui/dist/aws-icons/cloudfront.svg
21
+ backend/../ui/dist/aws-icons/cognito-idp.svg
22
+ backend/../ui/dist/aws-icons/dynamodb.svg
23
+ backend/../ui/dist/aws-icons/ec2.svg
24
+ backend/../ui/dist/aws-icons/ecr.svg
25
+ backend/../ui/dist/aws-icons/ecs.svg
26
+ backend/../ui/dist/aws-icons/elasticache.svg
27
+ backend/../ui/dist/aws-icons/elasticfilesystem.svg
28
+ backend/../ui/dist/aws-icons/elasticloadbalancing.svg
29
+ backend/../ui/dist/aws-icons/elasticmapreduce.svg
30
+ backend/../ui/dist/aws-icons/events.svg
31
+ backend/../ui/dist/aws-icons/firehose.svg
32
+ backend/../ui/dist/aws-icons/glue.svg
33
+ backend/../ui/dist/aws-icons/iam.svg
34
+ backend/../ui/dist/aws-icons/kinesis.svg
35
+ backend/../ui/dist/aws-icons/kms.svg
36
+ backend/../ui/dist/aws-icons/lambda.svg
37
+ backend/../ui/dist/aws-icons/logs.svg
38
+ backend/../ui/dist/aws-icons/monitoring.svg
39
+ backend/../ui/dist/aws-icons/rds.svg
40
+ backend/../ui/dist/aws-icons/route53.svg
41
+ backend/../ui/dist/aws-icons/s3.svg
42
+ backend/../ui/dist/aws-icons/secretsmanager.svg
43
+ backend/../ui/dist/aws-icons/ses.svg
44
+ backend/../ui/dist/aws-icons/sns.svg
45
+ backend/../ui/dist/aws-icons/sqs.svg
46
+ backend/../ui/dist/aws-icons/ssm.svg
47
+ backend/../ui/dist/aws-icons/stepfunctions.svg
48
+ backend/../ui/dist/aws-icons/wafv2.svg
49
+ backend/routes/__init__.py
50
+ backend/routes/dynamodb.py
51
+ backend/routes/ec2.py
52
+ backend/routes/iam.py
53
+ backend/routes/lambda_svc.py
54
+ backend/routes/logs.py
55
+ backend/routes/resources.py
56
+ backend/routes/s3.py
57
+ backend/routes/sqs.py
58
+ backend/routes/stats.py
59
+ stackport.egg-info/PKG-INFO
60
+ stackport.egg-info/SOURCES.txt
61
+ stackport.egg-info/dependency_links.txt
62
+ stackport.egg-info/entry_points.txt
63
+ stackport.egg-info/requires.txt
64
+ stackport.egg-info/top_level.txt
65
+ tests/test_cache.py
66
+ tests/test_client.py
67
+ tests/test_config.py
68
+ tests/test_dynamodb_routes.py
69
+ tests/test_ec2_routes.py
70
+ tests/test_iam_routes.py
71
+ tests/test_lambda_routes.py
72
+ tests/test_logs_routes.py
73
+ tests/test_registries.py
74
+ tests/test_routes.py
75
+ tests/test_sqs_routes.py
76
+ ui/dist/favicon.png
77
+ ui/dist/favicon.svg
78
+ ui/dist/index.html
79
+ ui/dist/assets/index-DI-V3ZCb.js
80
+ ui/dist/assets/index-DM3oKaVN.css
81
+ ui/dist/aws-icons/acm.svg
82
+ ui/dist/aws-icons/apigateway.svg
83
+ ui/dist/aws-icons/appsync.svg
84
+ ui/dist/aws-icons/athena.svg
85
+ ui/dist/aws-icons/cloudformation.svg
86
+ ui/dist/aws-icons/cloudfront.svg
87
+ ui/dist/aws-icons/cognito-idp.svg
88
+ ui/dist/aws-icons/dynamodb.svg
89
+ ui/dist/aws-icons/ec2.svg
90
+ ui/dist/aws-icons/ecr.svg
91
+ ui/dist/aws-icons/ecs.svg
92
+ ui/dist/aws-icons/elasticache.svg
93
+ ui/dist/aws-icons/elasticfilesystem.svg
94
+ ui/dist/aws-icons/elasticloadbalancing.svg
95
+ ui/dist/aws-icons/elasticmapreduce.svg
96
+ ui/dist/aws-icons/events.svg
97
+ ui/dist/aws-icons/firehose.svg
98
+ ui/dist/aws-icons/glue.svg
99
+ ui/dist/aws-icons/iam.svg
100
+ ui/dist/aws-icons/kinesis.svg
101
+ ui/dist/aws-icons/kms.svg
102
+ ui/dist/aws-icons/lambda.svg
103
+ ui/dist/aws-icons/logs.svg
104
+ ui/dist/aws-icons/monitoring.svg
105
+ ui/dist/aws-icons/rds.svg
106
+ ui/dist/aws-icons/route53.svg
107
+ ui/dist/aws-icons/s3.svg
108
+ ui/dist/aws-icons/secretsmanager.svg
109
+ ui/dist/aws-icons/ses.svg
110
+ ui/dist/aws-icons/sns.svg
111
+ ui/dist/aws-icons/sqs.svg
112
+ ui/dist/aws-icons/ssm.svg
113
+ ui/dist/aws-icons/stepfunctions.svg
114
+ ui/dist/aws-icons/wafv2.svg
@@ -23,6 +23,12 @@ class TestHealth:
23
23
  assert data["status"] == "ok"
24
24
  assert "uptime_seconds" in data
25
25
  assert isinstance(data["uptime_seconds"], (int, float))
26
+ assert "version" in data
27
+ assert isinstance(data["version"], str)
28
+ assert "endpoint_url" in data
29
+ assert "region" in data
30
+ assert "services_count" in data
31
+ assert isinstance(data["services_count"], int)
26
32
 
27
33
 
28
34
  class TestStats: