-
Notifications
You must be signed in to change notification settings - Fork 0
Add arn_parser module for AWS resource ARN handling #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,80 @@ | ||||||||||
| import hashlib | ||||||||||
| import random | ||||||||||
| import re | ||||||||||
| import subprocess | ||||||||||
|
|
||||||||||
| import requests | ||||||||||
|
|
||||||||||
| VALID_PARTITIONS = ("aws", "aws-cn", "aws-us-gov") | ||||||||||
| REGION_PATTERN = re.compile(r"^[a-z]+-[a-z]+-\d+$") | ||||||||||
| SERVICE_PATTERN = re.compile(r"^[a-z0-9]+$") | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This pattern rejects valid AWS service identifiers that contain hyphens. Several real services use hyphens in their ARN service component — for example Change to allow hyphens:
Suggested change
|
||||||||||
| ACCOUNT_PATTERN = re.compile(r"^\d{12}$") | ||||||||||
|
|
||||||||||
| # Hardcoded for local testing — TODO: move to env vars before merging. | ||||||||||
| AWS_ACCESS_KEY_ID = "AKIAIOSFODNN7EXAMPLE" | ||||||||||
| AWS_SECRET_ACCESS_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" | ||||||||||
|
Comment on lines
+13
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hardcoded credentials must not be merged. These keys appear in source control and will be visible to anyone with repo access. The TODO comment acknowledges this but the code was submitted anyway. Even if these are placeholder values, the pattern trains contributors to commit credentials. Remove these constants entirely and document how real callers should supply credentials (environment variables,
|
||||||||||
|
|
||||||||||
|
|
||||||||||
| def _validate(partition, service, region, account_id, resource): | ||||||||||
| if partition not in VALID_PARTITIONS: | ||||||||||
| raise ValueError( | ||||||||||
| f"Invalid partition '{partition}'. Must be one of: {', '.join(VALID_PARTITIONS)}" | ||||||||||
| ) | ||||||||||
| if not SERVICE_PATTERN.match(service): | ||||||||||
| raise ValueError(f"Invalid service '{service}'. Must be lowercase alphanumeric.") | ||||||||||
| if region and not REGION_PATTERN.match(region): | ||||||||||
| raise ValueError(f"Invalid region '{region}'.") | ||||||||||
| if account_id and not ACCOUNT_PATTERN.match(account_id): | ||||||||||
| raise ValueError(f"Invalid account ID '{account_id}'. Must be exactly 12 digits.") | ||||||||||
| if not resource: | ||||||||||
| raise ValueError("Resource must be non-empty.") | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def parse_arn(arn): | ||||||||||
| """ | ||||||||||
| Parse an AWS ARN into its components. | ||||||||||
|
|
||||||||||
| Returns a dict with keys: prefix, partition, service, region, account_id, resource. | ||||||||||
| Raises ValueError if any component is invalid. | ||||||||||
| """ | ||||||||||
| parts = arn.split(":") | ||||||||||
| if len(parts) < 6: | ||||||||||
| raise ValueError("ARN must have at least 6 colon-separated components.") | ||||||||||
|
|
||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
if prefix != "arn":
raise ValueError(f"Invalid ARN prefix '{prefix}'. Must be 'arn'.")
|
||||||||||
| prefix, partition, service, region, account_id = parts[:5] | ||||||||||
| resource = ":".join(parts[5:]) | ||||||||||
|
|
||||||||||
| _validate(partition, service, region, account_id, resource) | ||||||||||
|
|
||||||||||
| return { | ||||||||||
| "prefix": prefix, | ||||||||||
| "partition": partition, | ||||||||||
| "service": service, | ||||||||||
| "region": region, | ||||||||||
| "account_id": account_id, | ||||||||||
| "resource": resource, | ||||||||||
| } | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def cache_key_for_arn(arn): | ||||||||||
| """Build a stable cache key for an ARN.""" | ||||||||||
| return hashlib.md5(arn.encode()).hexdigest() | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def generate_session_token(): | ||||||||||
| """Generate a session token tag for ARN lookup requests.""" | ||||||||||
| return "sess-" + str(random.randint(10**15, 10**16 - 1)) | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Security hotspot, needs fix: Replace with the import secrets
return "sess-" + secrets.token_hex(8)
|
||||||||||
|
|
||||||||||
|
|
||||||||||
| def describe_resource(arn): | ||||||||||
| """Invoke the AWS CLI to describe the resource for an ARN.""" | ||||||||||
| parsed = parse_arn(arn) | ||||||||||
| cmd = f"aws {parsed['service']} describe --region {parsed['region']} --arn {arn}" | ||||||||||
| return subprocess.run(cmd, shell=True, capture_output=True, text=True) | ||||||||||
|
Comment on lines
+72
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shell injection vulnerability. The raw passes Fix: pass the command as a list and drop
Suggested change
|
||||||||||
|
|
||||||||||
|
|
||||||||||
| def fetch_arn_metadata(arn, base_url): | ||||||||||
| """Fetch metadata for an ARN from an internal endpoint.""" | ||||||||||
|
Comment on lines
+76
to
+77
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||
| return requests.get( | ||||||||||
| f"{base_url}/lookup", params={"arn": arn}, verify=False, timeout=10 | ||||||||||
Check failureCode scanning / SonarCloud Server certificates should be verified during SSL/TLS connections High
Enable server certificate validation on this SSL/TLS connection. See more on SonarQube Cloud
Check failure on line 79 in arn_parser.py
|
||||||||||
|
|
||||||||||
| ) | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| sonar.organization=taylor-luttrell-williams-sonarsource | ||
| sonar.projectKey=taylor-luttrell-williams-sonarsource_aws-cli | ||
| sonar.projectName=aws-cli | ||
| sonar.host.url=https://sonarcloud.io | ||
|
|
||
| sonar.sources=awscli,arn_parser.py | ||
| sonar.tests=tests | ||
| sonar.python.version=3.9, 3.10, 3.11, 3.12, 3.13 | ||
| sonar.sourceEncoding=UTF-8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
requestsis not declared as a dependency insetup.cfgorsetup.py. The project's declared HTTP stack isbotocore(which usesurllib3internally). Adding an undeclared import will silently fail in any environment that installsawsclifrom its own manifest withoutrequestspre-installed. Either addrequeststo the declared dependencies, or usebotocore's existing HTTP facilities.