pump-aws-radar 0.1.0__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.
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pump
4
+ Portions copyright (c) 2026 Mor Michaeli (upstream aws-radar, https://github.com/gomorsmi/aws-radar)
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,94 @@
1
+ Metadata-Version: 2.4
2
+ Name: pump-aws-radar
3
+ Version: 0.1.0
4
+ Summary: Fork of aws-radar that pushes AWS inventory + billing CSVs to Pump's self-serve onboarding
5
+ Author: Pump
6
+ Maintainer: Pump
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/meku-pump/pump-aws-radar
9
+ Project-URL: Repository, https://github.com/meku-pump/pump-aws-radar
10
+ Project-URL: Upstream, https://github.com/gomorsmi/aws-radar
11
+ Keywords: aws,cloud,inventory,cost-explorer,billing,finops,pump,onboarding
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: System :: Systems Administration
21
+ Classifier: Topic :: Utilities
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: boto3>=1.34.0
26
+ Requires-Dist: rich>=13.0.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7.0; extra == "dev"
29
+ Requires-Dist: build; extra == "dev"
30
+ Requires-Dist: twine; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # pump-aws-radar
34
+
35
+ A fork of [aws-radar](https://github.com/gomorsmi/aws-radar) that adds a one-command **push** of
36
+ your AWS inventory and billing CSVs to Pump's self-serve onboarding endpoint — no standing
37
+ cross-account role required.
38
+
39
+ Everything upstream (`inventory`, `billing`, `diagram`, `run`) works unchanged. The only addition is
40
+ `run --upload-token`.
41
+
42
+ ## Install
43
+
44
+ ```bash
45
+ pip install pump-aws-radar
46
+ ```
47
+
48
+ The console script is `pump-aws-radar`, so it installs alongside upstream `aws-radar` without
49
+ colliding.
50
+
51
+ ## Pump onboarding
52
+
53
+ 1. In the Pump app, mint an upload token (this calls `POST /api/v1/estimate/radar/mint`). Pump shows
54
+ you a ready-to-paste command.
55
+ 2. Run it against the AWS account you want to onboard:
56
+
57
+ ```bash
58
+ pump-aws-radar run --all-regions --tags --billing --upload-token <TOKEN>
59
+ ```
60
+
61
+ This inventories the account read-only, pulls Cost Explorer billing, and uploads both
62
+ `inventory.csv` and `billing.csv` straight to Pump. No diagram is generated on this path.
63
+ 3. Pump detects both files, runs its analysis, and surfaces the findings in the app.
64
+
65
+ ### What leaves your machine
66
+
67
+ Only the two CSVs. The token carries no AWS credentials and no company id — Pump binds the company
68
+ and derives the S3 key server-side, so a token can only ever write its own upload's prefix. Each file
69
+ goes to S3 through a short-lived presigned `PUT` URL that Pump mints on demand.
70
+
71
+ ### Pointing at a non-prod backend
72
+
73
+ The token exchange defaults to `https://api.pump.co`. Override it for local testing:
74
+
75
+ ```bash
76
+ pump-aws-radar run --billing --upload-token <TOKEN> --api-base http://localhost:8001
77
+ # or
78
+ PUMP_API_BASE=http://localhost:8001 pump-aws-radar run --billing --upload-token <TOKEN>
79
+ ```
80
+
81
+ ## How the push works
82
+
83
+ `pump_aws_radar/upload.py`:
84
+
85
+ 1. For each role (`inventory`, `billing`), `POST {api_base}/api/v1/estimate/radar/urls` with
86
+ `{"token", "role"}` and receives a presigned S3 `PUT` URL.
87
+ 2. `PUT`s the corresponding CSV with `Content-Type: text/csv` (the presigned URL signs the
88
+ content-type, so it must match).
89
+
90
+ ## Relationship to upstream
91
+
92
+ This is a derivative work of [aws-radar](https://github.com/gomorsmi/aws-radar), MIT-licensed, with
93
+ upstream copyright preserved in `LICENSE`. The scanning, billing, and diagram code is upstream's; the
94
+ Pump push is the fork's addition.
@@ -0,0 +1,62 @@
1
+ # pump-aws-radar
2
+
3
+ A fork of [aws-radar](https://github.com/gomorsmi/aws-radar) that adds a one-command **push** of
4
+ your AWS inventory and billing CSVs to Pump's self-serve onboarding endpoint — no standing
5
+ cross-account role required.
6
+
7
+ Everything upstream (`inventory`, `billing`, `diagram`, `run`) works unchanged. The only addition is
8
+ `run --upload-token`.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pip install pump-aws-radar
14
+ ```
15
+
16
+ The console script is `pump-aws-radar`, so it installs alongside upstream `aws-radar` without
17
+ colliding.
18
+
19
+ ## Pump onboarding
20
+
21
+ 1. In the Pump app, mint an upload token (this calls `POST /api/v1/estimate/radar/mint`). Pump shows
22
+ you a ready-to-paste command.
23
+ 2. Run it against the AWS account you want to onboard:
24
+
25
+ ```bash
26
+ pump-aws-radar run --all-regions --tags --billing --upload-token <TOKEN>
27
+ ```
28
+
29
+ This inventories the account read-only, pulls Cost Explorer billing, and uploads both
30
+ `inventory.csv` and `billing.csv` straight to Pump. No diagram is generated on this path.
31
+ 3. Pump detects both files, runs its analysis, and surfaces the findings in the app.
32
+
33
+ ### What leaves your machine
34
+
35
+ Only the two CSVs. The token carries no AWS credentials and no company id — Pump binds the company
36
+ and derives the S3 key server-side, so a token can only ever write its own upload's prefix. Each file
37
+ goes to S3 through a short-lived presigned `PUT` URL that Pump mints on demand.
38
+
39
+ ### Pointing at a non-prod backend
40
+
41
+ The token exchange defaults to `https://api.pump.co`. Override it for local testing:
42
+
43
+ ```bash
44
+ pump-aws-radar run --billing --upload-token <TOKEN> --api-base http://localhost:8001
45
+ # or
46
+ PUMP_API_BASE=http://localhost:8001 pump-aws-radar run --billing --upload-token <TOKEN>
47
+ ```
48
+
49
+ ## How the push works
50
+
51
+ `pump_aws_radar/upload.py`:
52
+
53
+ 1. For each role (`inventory`, `billing`), `POST {api_base}/api/v1/estimate/radar/urls` with
54
+ `{"token", "role"}` and receives a presigned S3 `PUT` URL.
55
+ 2. `PUT`s the corresponding CSV with `Content-Type: text/csv` (the presigned URL signs the
56
+ content-type, so it must match).
57
+
58
+ ## Relationship to upstream
59
+
60
+ This is a derivative work of [aws-radar](https://github.com/gomorsmi/aws-radar), MIT-licensed, with
61
+ upstream copyright preserved in `LICENSE`. The scanning, billing, and diagram code is upstream's; the
62
+ Pump push is the fork's addition.
@@ -0,0 +1,59 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pump-aws-radar"
7
+ version = "0.1.0"
8
+ description = "Fork of aws-radar that pushes AWS inventory + billing CSVs to Pump's self-serve onboarding"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ { name = "Pump" },
14
+ ]
15
+ maintainers = [
16
+ { name = "Pump" },
17
+ ]
18
+ keywords = ["aws", "cloud", "inventory", "cost-explorer", "billing", "finops", "pump", "onboarding"]
19
+ classifiers = [
20
+ "Development Status :: 4 - Beta",
21
+ "Intended Audience :: Developers",
22
+ "Intended Audience :: System Administrators",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.9",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Topic :: System :: Systems Administration",
29
+ "Topic :: Utilities",
30
+ ]
31
+ dependencies = [
32
+ "boto3>=1.34.0",
33
+ "rich>=13.0.0",
34
+ ]
35
+
36
+ [project.optional-dependencies]
37
+ dev = [
38
+ "pytest>=7.0",
39
+ "build",
40
+ "twine",
41
+ ]
42
+
43
+ [project.urls]
44
+ Homepage = "https://github.com/meku-pump/pump-aws-radar"
45
+ Repository = "https://github.com/meku-pump/pump-aws-radar"
46
+ Upstream = "https://github.com/gomorsmi/aws-radar"
47
+
48
+ [project.scripts]
49
+ pump-aws-radar = "pump_aws_radar.__main__:main"
50
+
51
+ [tool.setuptools.packages.find]
52
+ where = ["src"]
53
+
54
+ [tool.setuptools.package-dir]
55
+ "" = "src"
56
+
57
+ [tool.pytest.ini_options]
58
+ testpaths = ["tests"]
59
+ addopts = "-v --tb=short"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,14 @@
1
+ """
2
+ pump-aws-radar — a fork of aws-radar (gomorsmi/aws-radar) that adds a one-command
3
+ push of the inventory + billing CSVs to Pump's self-serve onboarding endpoint.
4
+
5
+ Upstream scans an AWS account read-only and writes a CSV inventory, a Cost Explorer
6
+ billing CSV, and a draw.io diagram. This fork adds `run --upload-token`, which sends
7
+ the two CSVs to Pump instead of drawing a diagram (see pump_aws_radar.upload).
8
+
9
+ Quick start (Pump onboarding):
10
+ pump-aws-radar run --all-regions --tags --billing --upload-token <TOKEN>
11
+ """
12
+
13
+ __version__ = "0.1.0"
14
+ __author__ = "Pump (fork of aws-radar by Mor Michaeli)"
@@ -0,0 +1,201 @@
1
+ """
2
+ Entry point for:
3
+ python -m pump_aws_radar
4
+ pump-aws-radar (after pip install)
5
+
6
+ This is a fork of gomorsmi/aws-radar. The only functional addition is the
7
+ `run --upload-token` path, which pushes the inventory and billing CSVs to Pump's
8
+ self-serve onboarding endpoint (see pump_aws_radar.upload).
9
+ """
10
+
11
+ import argparse
12
+ import os
13
+ import sys
14
+
15
+ # Mirrors pump_aws_radar.billing.METRICS. Duplicated here so `--help` works without
16
+ # boto3 installed — importing billing pulls in boto3 at module scope.
17
+ # tests/test_pump_aws_radar.py keeps the two lists in sync.
18
+ METRICS = [
19
+ "UnblendedCost", "AmortizedCost", "BlendedCost",
20
+ "NetUnblendedCost", "NetAmortizedCost", "UsageQuantity",
21
+ ]
22
+
23
+ # Where the Pump backend lives. Overridable for local testing via --api-base or
24
+ # the PUMP_API_BASE env var (e.g. http://localhost:8001).
25
+ DEFAULT_API_BASE = os.environ.get("PUMP_API_BASE", "https://api.pump.co")
26
+
27
+
28
+ def main():
29
+ parser = argparse.ArgumentParser(
30
+ prog="pump-aws-radar",
31
+ description="AWS resource inventory & draw.io architecture diagram generator",
32
+ )
33
+ sub = parser.add_subparsers(dest="command", required=True)
34
+
35
+ # ── inventory sub-command ──
36
+ inv = sub.add_parser("inventory", help="Scan AWS account and list all resources")
37
+ inv.add_argument("--region", default=None, help="AWS region (default: boto3 default)")
38
+ inv.add_argument("--profile", default=None, help="AWS SSO/named profile")
39
+ inv.add_argument("--role-arn", default=None, help="IAM role ARN to assume")
40
+ inv.add_argument("--all-regions", action="store_true", help="Scan all enabled regions")
41
+ inv.add_argument("--ai", action=argparse.BooleanOptionalAction, default=True,
42
+ help="Scan AI/ML services (Bedrock, SageMaker, Rekognition, Lex, Kendra, …). On by default; pass --no-ai to skip them")
43
+ inv.add_argument("--tags", action="store_true", help="Fetch resource tags and add a 'Tags' column")
44
+ inv.add_argument("--tags-wide", action="store_true", help="Also write a CSV with one column per tag key (implies --tags)")
45
+ inv.add_argument("--cost-allocation-tags", action="store_true", help="Add a 'CostAllocTags' column with billing-activated tags (implies --tags)")
46
+ inv.add_argument("--include-aws-tags", action="store_true", help="Include aws:-prefixed system tags (excluded by default)")
47
+ inv.add_argument("--billing", action="store_true", help="Also pull Cost Explorer daily cost by service and write a CSV")
48
+ inv.add_argument("--billing-days", type=int, default=None, help="Billing window in days (default: 90)")
49
+ inv.add_argument("--billing-metric", default=None, choices=METRICS, help="Cost Explorer metric (default: UnblendedCost)")
50
+ inv.add_argument("--billing-output", metavar="FILE.csv", default=None, help="Billing CSV path (default: billing.csv)")
51
+ inv.add_argument("--include-zero", action="store_true", help="Keep zero-cost service/day buckets in the billing CSV")
52
+ inv.add_argument("--export", metavar="FILE.csv", help="Export results to CSV")
53
+
54
+ # ── billing sub-command ──
55
+ bil = sub.add_parser("billing", help="Pull Cost Explorer daily cost by service to CSV")
56
+ bil.add_argument("--profile", default=None, help="AWS SSO/named profile")
57
+ bil.add_argument("--days", type=int, default=90, help="Trailing window in days (default: 90)")
58
+ bil.add_argument("--metric", default="UnblendedCost", choices=METRICS, help="Cost Explorer metric (default: UnblendedCost)")
59
+ bil.add_argument("--include-zero", action="store_true", help="Keep service/day buckets with zero cost")
60
+ bil.add_argument("--output", metavar="FILE.csv", default="billing.csv", help="CSV output path (default: billing.csv)")
61
+
62
+ # ── diagram sub-command ──
63
+ dia = sub.add_parser("diagram", help="Generate draw.io diagram from inventory CSV")
64
+ dia.add_argument("--input", required=True, help="CSV produced by 'inventory'")
65
+ dia.add_argument("--output", default="architecture.drawio", help="Output .drawio file")
66
+
67
+ # ── all-in-one sub-command ──
68
+ run = sub.add_parser("run", help="Inventory + diagram in one shot (or push CSVs to Pump)")
69
+ run.add_argument("--region", default=None)
70
+ run.add_argument("--profile", default=None)
71
+ run.add_argument("--role-arn", default=None)
72
+ run.add_argument("--all-regions", action="store_true")
73
+ run.add_argument("--ai", action=argparse.BooleanOptionalAction, default=True,
74
+ help="Scan AI/ML services (on by default; --no-ai to skip)")
75
+ run.add_argument("--tags", action="store_true", help="Fetch resource tags and add a 'Tags' column")
76
+ run.add_argument("--tags-wide", action="store_true", help="Also write a CSV with one column per tag key (implies --tags)")
77
+ run.add_argument("--cost-allocation-tags", action="store_true", help="Add a 'CostAllocTags' column with billing-activated tags (implies --tags)")
78
+ run.add_argument("--include-aws-tags", action="store_true", help="Include aws:-prefixed system tags (excluded by default)")
79
+ run.add_argument("--billing", action="store_true", help="Also pull Cost Explorer daily cost by service and write a CSV")
80
+ run.add_argument("--billing-days", type=int, default=None, help="Billing window in days (default: 90)")
81
+ run.add_argument("--billing-metric", default=None, choices=METRICS, help="Cost Explorer metric (default: UnblendedCost)")
82
+ run.add_argument("--billing-output", metavar="FILE.csv", default=None, help="Billing CSV path (default: billing.csv)")
83
+ run.add_argument("--include-zero", action="store_true", help="Keep zero-cost service/day buckets in the billing CSV")
84
+ run.add_argument("--csv", default="inventory.csv", help="Intermediate CSV path")
85
+ run.add_argument("--output", default="architecture.drawio", help="Output .drawio file")
86
+ # ── Pump onboarding push (fork addition) ──
87
+ run.add_argument("--upload-token", default=None,
88
+ help="Pump upload token: push the inventory + billing CSVs to Pump instead of drawing a diagram")
89
+ run.add_argument("--api-base", default=DEFAULT_API_BASE,
90
+ help=f"Pump API base for --upload-token (default: {DEFAULT_API_BASE}; or set PUMP_API_BASE)")
91
+
92
+ args = parser.parse_args()
93
+
94
+ if args.command == "inventory":
95
+ from pump_aws_radar.inventory import main as inv_main
96
+ sys.argv = _rebuild_argv("inventory", args)
97
+ inv_main()
98
+
99
+ elif args.command == "billing":
100
+ from pump_aws_radar.billing import main as bil_main
101
+ sys.argv = _rebuild_argv("billing", args)
102
+ bil_main()
103
+
104
+ elif args.command == "diagram":
105
+ from pump_aws_radar.drawio import main as dia_main
106
+ sys.argv = _rebuild_argv("diagram", args)
107
+ dia_main()
108
+
109
+ elif args.command == "run":
110
+ _run(args)
111
+
112
+
113
+ def _run(args):
114
+ from pump_aws_radar.inventory import main as inv_main
115
+
116
+ uploading = bool(args.upload_token)
117
+ # The Pump flow needs both CSVs: the backend only starts analysis once
118
+ # inventory.csv and billing.csv are both present.
119
+ if uploading and not args.billing:
120
+ sys.exit(
121
+ "Error: --upload-token requires --billing so both CSVs are produced.\n"
122
+ "Run: pump-aws-radar run --all-regions --tags --billing --upload-token <TOKEN>"
123
+ )
124
+
125
+ total = 2 if uploading else 2
126
+ # Step 1 — inventory (and billing, when --billing is set)
127
+ print(f"── Step 1/{total}: Running inventory ──")
128
+ inv_args = ["pump-aws-radar"]
129
+ if args.profile: inv_args += ["--profile", args.profile]
130
+ if args.role_arn: inv_args += ["--role-arn", args.role_arn]
131
+ if args.region: inv_args += ["--region", args.region]
132
+ if args.all_regions: inv_args += ["--all-regions"]
133
+ # Ternary, not `if args.ai:` — a bare if would emit nothing for --no-ai
134
+ # and let inventory.py's own default (True) decide instead.
135
+ inv_args += ["--ai"] if args.ai else ["--no-ai"]
136
+ if args.tags: inv_args += ["--tags"]
137
+ if args.tags_wide: inv_args += ["--tags-wide"]
138
+ if args.cost_allocation_tags: inv_args += ["--cost-allocation-tags"]
139
+ if args.include_aws_tags: inv_args += ["--include-aws-tags"]
140
+ if args.billing: inv_args += ["--billing"]
141
+ if args.billing_days is not None: inv_args += ["--billing-days", str(args.billing_days)]
142
+ if args.billing_metric: inv_args += ["--billing-metric", args.billing_metric]
143
+ if args.billing_output: inv_args += ["--billing-output", args.billing_output]
144
+ if args.include_zero: inv_args += ["--include-zero"]
145
+ inv_args += ["--export", args.csv]
146
+ sys.argv = inv_args
147
+ inv_main()
148
+
149
+ if uploading:
150
+ # Step 2 — push both CSVs to Pump
151
+ from pump_aws_radar.upload import UploadError, upload_csvs
152
+
153
+ billing_csv = args.billing_output or "billing.csv"
154
+ print(f"\n── Step 2/{total}: Uploading to Pump ({args.api_base}) ──")
155
+ try:
156
+ upload_csvs(
157
+ api_base=args.api_base,
158
+ token=args.upload_token,
159
+ files={"inventory": args.csv, "billing": billing_csv},
160
+ )
161
+ except UploadError as e:
162
+ sys.exit(f"\nUpload failed: {e}")
163
+ print("\n✓ Done! Your inventory and billing data are on their way to Pump.")
164
+ return
165
+
166
+ # Step 2 — diagram (default, non-upload path)
167
+ from pump_aws_radar.drawio import main as dia_main
168
+
169
+ print(f"\n── Step 2/{total}: Generating diagram ──")
170
+ sys.argv = ["pump-aws-radar", "--input", args.csv, "--output", args.output]
171
+ dia_main()
172
+ print(f"\n✓ Done! Open {args.output} at https://app.diagrams.net/")
173
+
174
+
175
+ # Dests whose False value is meaningful and so must be forwarded explicitly.
176
+ # inventory.py re-parses this argv with its own parser and its own defaults, so
177
+ # a flag omitted here is decided by that parser, not by the user. That is only
178
+ # correct for plain store_true flags, which default to False on both sides.
179
+ NEGATABLE = {"inventory": {"ai"}, "run": {"ai"}}
180
+
181
+
182
+ def _rebuild_argv(cmd, args):
183
+ argv = ["pump-aws-radar"]
184
+ negatable = NEGATABLE.get(cmd, frozenset())
185
+ d = vars(args)
186
+ for k, v in d.items():
187
+ if k == "command":
188
+ continue
189
+ flag = "--" + k.replace("_", "-")
190
+ if isinstance(v, bool):
191
+ if v:
192
+ argv.append(flag)
193
+ elif k in negatable:
194
+ argv.append("--no-" + k.replace("_", "-"))
195
+ elif v is not None:
196
+ argv += [flag, str(v)]
197
+ return argv
198
+
199
+
200
+ if __name__ == "__main__":
201
+ main()