swa 0.8.6 → 1.0.0
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.
- checksums.yaml +4 -4
- data/.beads/.gitignore +18 -0
- data/.beads/issues.jsonl +5 -0
- data/.rubocop.yml +39 -0
- data/AGENTS.md +541 -0
- data/CLAUDE.md +5 -0
- data/Gemfile +9 -1
- data/README.md +0 -5
- data/Rakefile +2 -0
- data/bin/console +1 -0
- data/exe/swa +2 -1
- data/lib/swa/athena/catalog.rb +4 -0
- data/lib/swa/athena/database.rb +4 -0
- data/lib/swa/athena/query_execution.rb +4 -0
- data/lib/swa/athena/work_group.rb +4 -0
- data/lib/swa/cli/athena_command.rb +93 -42
- data/lib/swa/cli/base_command.rb +22 -14
- data/lib/swa/cli/cloud_formation_command.rb +11 -4
- data/lib/swa/cli/cloudtrail_command.rb +130 -0
- data/lib/swa/cli/collection_behaviour.rb +4 -2
- data/lib/swa/cli/data_output.rb +12 -11
- data/lib/swa/cli/ec2_command.rb +21 -37
- data/lib/swa/cli/elb_command.rb +5 -3
- data/lib/swa/cli/filter_options.rb +6 -1
- data/lib/swa/cli/glue_command.rb +84 -36
- data/lib/swa/cli/iam_command.rb +42 -33
- data/lib/swa/cli/item_behaviour.rb +4 -2
- data/lib/swa/cli/kms_command.rb +26 -5
- data/lib/swa/cli/lake_formation_command.rb +72 -11
- data/lib/swa/cli/main_command.rb +19 -9
- data/lib/swa/cli/s3_command.rb +32 -24
- data/lib/swa/cli/selector.rb +4 -0
- data/lib/swa/cli/tag_filter_options.rb +6 -2
- data/lib/swa/cloud_formation/stack.rb +5 -1
- data/lib/swa/cloud_trail/event.rb +49 -0
- data/lib/swa/data_presentation.rb +23 -22
- data/lib/swa/ec2/image.rb +7 -5
- data/lib/swa/ec2/instance.rb +5 -1
- data/lib/swa/ec2/key_pair.rb +4 -0
- data/lib/swa/ec2/security_group.rb +5 -3
- data/lib/swa/ec2/snapshot.rb +6 -4
- data/lib/swa/ec2/subnet.rb +5 -3
- data/lib/swa/ec2/tagged_resource.rb +4 -0
- data/lib/swa/ec2/volume.rb +7 -5
- data/lib/swa/ec2/vpc.rb +5 -3
- data/lib/swa/elb/load_balancer.rb +4 -0
- data/lib/swa/glue/crawl.rb +5 -1
- data/lib/swa/glue/crawler.rb +5 -1
- data/lib/swa/glue/database.rb +5 -0
- data/lib/swa/glue/job.rb +4 -0
- data/lib/swa/glue/job_bookmark_entry.rb +4 -0
- data/lib/swa/glue/job_run.rb +5 -1
- data/lib/swa/glue/partition.rb +5 -1
- data/lib/swa/glue/table.rb +4 -0
- data/lib/swa/iam/credentials.rb +7 -7
- data/lib/swa/iam/group.rb +5 -3
- data/lib/swa/iam/instance_profile.rb +5 -3
- data/lib/swa/iam/policy.rb +5 -3
- data/lib/swa/iam/role.rb +10 -3
- data/lib/swa/iam/role_policy.rb +5 -3
- data/lib/swa/iam/user.rb +5 -3
- data/lib/swa/kms/alias.rb +4 -0
- data/lib/swa/kms/key.rb +4 -0
- data/lib/swa/lake_formation/data_lake_settings.rb +15 -0
- data/lib/swa/lake_formation/permission.rb +5 -1
- data/lib/swa/lake_formation/resource_info.rb +4 -0
- data/lib/swa/lake_formation/tag.rb +25 -0
- data/lib/swa/polyfill.rb +3 -1
- data/lib/swa/record.rb +5 -3
- data/lib/swa/resource.rb +3 -1
- data/lib/swa/s3/bucket.rb +5 -3
- data/lib/swa/s3/object.rb +7 -5
- data/lib/swa/s3/object_list_entry.rb +4 -0
- data/lib/swa/s3/object_version.rb +13 -7
- data/lib/swa/version.rb +5 -1
- data/lib/swa.rb +2 -0
- data/swa.gemspec +29 -25
- metadata +63 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7881424f25a25e4b4eaabbeb23b23661ca08294c2b7a766a8463ad111a0a31c7
|
|
4
|
+
data.tar.gz: b35dde4b7c9e44486eb61b31f9cec0bf3656d8f7c539e2e9f80a1dc128e49fc5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f494cf53c307bb2a6c9603ad59c6912a0371192184c5a2934a55aa0c8cadb692e18148481d306ee124b7113ce02b646e7972fbd2aa1ee2b0def09f778eb1e9be
|
|
7
|
+
data.tar.gz: 94576ae0691f6b37caccaf7da735b02f107737da10c5ac2781825c90e0fd8439fbb86843039f12a96266ee0c1bd2530f1f39224be21c83823ae0ab8a755cc1b1
|
data/.beads/.gitignore
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# SQLite databases
|
|
2
|
+
*.db
|
|
3
|
+
*.db-journal
|
|
4
|
+
*.db-wal
|
|
5
|
+
*.db-shm
|
|
6
|
+
|
|
7
|
+
# Daemon runtime files
|
|
8
|
+
daemon.lock
|
|
9
|
+
daemon.log
|
|
10
|
+
daemon.pid
|
|
11
|
+
bd.sock
|
|
12
|
+
|
|
13
|
+
# Legacy database files
|
|
14
|
+
db.sqlite
|
|
15
|
+
bd.db
|
|
16
|
+
|
|
17
|
+
# Keep JSONL exports (source of truth for git)
|
|
18
|
+
!*.jsonl
|
data/.beads/issues.jsonl
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{"id":"swa-1","title":"Add CloudTrail support with \"swa cloudtrail query\" command","description":"Implement CloudTrail support in swa to enable querying CloudTrail events. Initial implementation should support \"swa cloudtrail query\" to return the most recent 50 CloudTrail entries. Future enhancements will add filtering and ordering options.","design":"Follow the existing swa architecture patterns:\n\n1. Add aws-sdk-cloudtrail dependency to swa.gemspec\n2. Create lib/swa/cloud_trail/ directory for resource models\n3. Create lib/swa/cloud_trail/event.rb to wrap CloudTrail event records\n4. Create lib/swa/cli/cloud_trail_command.rb following pattern of other service commands\n5. Implement \"query\" subcommand using CollectionBehaviour mixin\n6. Use CloudTrail LookupEvents API to fetch recent events (default limit: 50)\n7. Implement summary() method for one-line event display\n8. Support standard data output (YAML/JSON with JMESPath)\n\nThe command structure should be:\n- swa cloudtrail query summary (default)\n- swa cloudtrail query data [jmespath-query]","acceptance_criteria":"- Running \"swa cloudtrail query\" returns the 50 most recent CloudTrail events\n- Output defaults to summary format (one line per event)\n- \"swa cloudtrail query data\" returns full event data in YAML\n- \"swa cloudtrail query data --json\" returns full event data in JSON\n- JMESPath queries work with the data output\n- Event summary shows key fields (timestamp, event name, username, source IP)\n- Follows existing swa architectural patterns and code style","notes":"Implemented and tested CloudTrail support. All acceptance criteria met:\n- Returns 50 most recent events by default\n- --limit option works correctly (fixed in commit 3012838)\n- Summary format shows timestamp, event name, username, event source\n- Data output in YAML/JSON works\n- JMESPath queries work\n- Follows swa architectural patterns","status":"closed","priority":2,"issue_type":"feature","assignee":"mikewilliams","created_at":"2025-10-25T16:03:46.156464+11:00","updated_at":"2025-10-26T10:19:01.802715+11:00","closed_at":"2025-10-26T10:19:01.802715+11:00"}
|
|
2
|
+
{"id":"swa-2","title":"Add filtering options for cloudtrail events","description":"Add command-line options to filter CloudTrail events by common criteria like event source and event name. This will make it easier to narrow down results without piping through grep/jq.","design":"Add filtering options to the cloudtrail events command:\n\nOptions to add:\n- --source SERVICE - filter by event source (e.g., kms.amazonaws.com, sts.amazonaws.com)\n- --name EVENT_NAME - filter by event name (e.g., Decrypt, AssumeRole)\n\nImplementation approach:\n1. Add option declarations in cloudtrail_command.rb\n2. Apply filters to the collection before .take(max)\n3. Use lazy evaluation to maintain efficiency\n4. Consider using AWS CloudTrail LookupEvents API filters if available (check API docs)\n - If API supports filtering, pass to lookup_events\n - Otherwise, filter in Ruby after fetching\n\nFuture enhancements could add:\n- --user USERNAME - filter by username\n- --since/--until - time range filtering\n- --resource - filter by resource type/ARN","acceptance_criteria":"- Can filter by event source: swa cloudtrail events --source kms.amazonaws.com\n- Can filter by event name: swa cloudtrail events --name Decrypt\n- Can combine filters: swa cloudtrail events --source sts.amazonaws.com --name AssumeRole\n- Filters work with all output modes (summary, data)\n- Filters work correctly with --max option\n- Performance is reasonable (uses API filters if available)","notes":"Implemented filtering options for CloudTrail events:\n- Added --source option to filter by event source (e.g. kms.amazonaws.com)\n- Added --name option to filter by event name (e.g. Decrypt)\n- Handles CloudTrail API limitation (only one lookup_attribute at a time) by using most selective filter at API level and applying second filter in Ruby\n- All tests passing with various filter combinations\n- Works with all output modes (summary, data)","status":"closed","priority":2,"issue_type":"feature","assignee":"mikewilliams","created_at":"2025-10-25T16:55:05.923645+11:00","updated_at":"2025-10-25T22:34:46.729002+11:00","closed_at":"2025-10-25T22:34:46.729002+11:00"}
|
|
3
|
+
{"id":"swa-3","title":"Add filtering by caller for cloudtrail events","description":"Add ability to filter CloudTrail events by the identity/caller that made the API call. This is useful for tracking down specific users, roles, or service accounts.","design":"Add --user/--caller option to filter CloudTrail events by the identity making the request.\n\nThe CloudTrail event structure has multiple identity-related fields:\n- username (from envelope) - simplified identity string\n- userIdentity.principalId (in CloudTrail event)\n- userIdentity.arn (in CloudTrail event) \n- userIdentity.userName (in CloudTrail event)\n\nImplementation approach:\n1. Add --user USERNAME option (or --caller)\n2. Consider matching against multiple fields for flexibility:\n - Match against username field (envelope)\n - Could also match against userIdentity.principalId or userName\n3. Support partial matching (substring) for convenience\n4. Investigate if CloudTrail LookupEvents API supports username filtering\n\nExamples:\n- swa cloudtrail events --user snowflake\n- swa cloudtrail events --user kafkatopicarchive\n- swa cloudtrail events --user system:serviceaccount\n\nConsider if this should be combined with swa-2 (general filtering) or kept separate.","acceptance_criteria":"- Can filter by caller/user: swa cloudtrail events --user USERNAME\n- Partial matching works (e.g., --user kafka matches kafkatopicarchive-*)\n- Works with other filters and --max option\n- Works with all output modes (summary, data)\n- Helpful error message if no events match the filter","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-25T16:55:56.999516+11:00","updated_at":"2025-10-25T22:48:57.404314+11:00","closed_at":"2025-10-25T22:48:57.404314+11:00"}
|
|
4
|
+
{"id":"swa-4","title":"Add general --where filtering for CloudTrail events","description":"Add a flexible --where option that allows filtering CloudTrail events by any field in the CloudTrail event structure using a key=value or key=pattern syntax. This provides more flexible filtering than the specific --source and --name options.","design":"Add --where option for general field matching:\n\nSyntax: --where FIELD=VALUE\n- FIELD: JMESPath-style field path (e.g., awsRegion, userIdentity.type)\n- VALUE: String or wildcard pattern (supports * and ?)\n- Can be specified multiple times (AND logic)\n\nExamples:\n- swa cloudtrail events --where awsRegion=us-west-2\n- swa cloudtrail events --where userIdentity.type=AssumedRole\n- swa cloudtrail events --where userIdentity.sessionContext.sessionIssuer.arn=*:role/emr-iceberg-stats\n- swa cloudtrail events --where eventType=AwsApiCall --where readOnly=false\n\nImplementation approach:\n1. Accept multiple --where options (Clamp supports this)\n2. Parse each into field path and pattern\n3. Extract field values from CloudTrail event using JMESPath or nested hash access\n4. Match using compiled patterns (same as --name and --source)\n5. All --where conditions must match (AND logic)\n\nSince CloudTrail API doesn't support arbitrary field filtering, all filtering will be done in Ruby after fetching events.\n\nNote: This is complementary to --source and --name, which use API filtering when possible.","acceptance_criteria":"- Can filter by any field: swa cloudtrail events --where awsRegion=us-west-2\n- Supports nested fields: --where userIdentity.type=AssumedRole\n- Supports wildcards: --where sourceIPAddress=10.0.*\n- Multiple --where conditions work (AND logic)\n- Works with --source, --name, and --max options\n- Works with all output modes\n- Clear error message if field path is invalid","status":"closed","priority":2,"issue_type":"feature","assignee":"mikewilliams","created_at":"2025-10-25T22:38:44.843229+11:00","updated_at":"2025-10-26T10:16:23.846637+11:00","closed_at":"2025-10-26T10:16:23.846637+11:00"}
|
|
5
|
+
{"id":"swa-5","title":"Add time-based filtering with --after and --before options","description":"Add --after and --before options to cloudtrail events command to filter events by time range. Use the existing parse_datetime function from base_command.rb to parse time arguments and pass StartTime and EndTime parameters to the CloudTrail LookupEvents API.","design":"Add time-based filtering options to cloudtrail events command:\n\nOptions to add:\n- --after TIME - filter events after this time\n- --before TIME - filter events before this time\n\nImplementation approach:\n1. Add option declarations in cloudtrail_command.rb\n2. Use parse_datetime function from base_command.rb (line 66) to parse time arguments\n3. Pass StartTime and EndTime parameters to CloudTrail LookupEvents API\n - StartTime: corresponds to --after\n - EndTime: corresponds to --before\n4. CloudTrail API supports these natively, so filtering happens at API level\n\nparse_datetime supports various formats:\n- Absolute: \"2025-01-15\", \"2025-01-15 14:30\"\n- Relative: \"yesterday\", \"last week\", \"2 days ago\"\n- Uses Chronic gem for natural language parsing\n\nExamples:\n- swa cloudtrail events --after \"last week\"\n- swa cloudtrail events --before \"2025-01-20\"\n- swa cloudtrail events --after \"yesterday\" --before \"today\"","acceptance_criteria":"- Can filter events after a time: swa cloudtrail events --after \"last week\"\n- Can filter events before a time: swa cloudtrail events --before \"2025-01-20\"\n- Can combine time filters: swa cloudtrail events --after \"yesterday\" --before \"today\"\n- Supports relative time expressions via parse_datetime\n- Works with other filters (--source, --name, --max)\n- Works with all output modes (summary, data)\n- Clear error message if time parsing fails","status":"closed","priority":2,"issue_type":"feature","assignee":"mikewilliams","created_at":"2025-10-25T22:42:48.949746+11:00","updated_at":"2025-10-25T22:54:47.74188+11:00","closed_at":"2025-10-25T22:54:47.74188+11:00"}
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
NewCops: enable
|
|
3
|
+
SuggestExtensions: false
|
|
4
|
+
|
|
5
|
+
Layout/EmptyLinesAroundBlockBody:
|
|
6
|
+
Enabled: false
|
|
7
|
+
EnforcedStyle: empty_lines
|
|
8
|
+
Layout/EmptyLinesAroundClassBody:
|
|
9
|
+
EnforcedStyle: empty_lines
|
|
10
|
+
Layout/EmptyLinesAroundModuleBody:
|
|
11
|
+
EnforcedStyle: empty_lines
|
|
12
|
+
|
|
13
|
+
Lint/DuplicateBranch:
|
|
14
|
+
Enabled: false
|
|
15
|
+
Lint/NestedMethodDefinition:
|
|
16
|
+
Enabled: false
|
|
17
|
+
|
|
18
|
+
Metrics/AbcSize:
|
|
19
|
+
Max: 40
|
|
20
|
+
Metrics/BlockLength:
|
|
21
|
+
Max: 25
|
|
22
|
+
AllowedMethods:
|
|
23
|
+
- subcommand
|
|
24
|
+
Metrics/ClassLength:
|
|
25
|
+
Enabled: false
|
|
26
|
+
Metrics/CyclomaticComplexity:
|
|
27
|
+
Max: 15
|
|
28
|
+
Metrics/MethodLength:
|
|
29
|
+
Max: 30
|
|
30
|
+
Metrics/PerceivedComplexity:
|
|
31
|
+
Max: 15
|
|
32
|
+
|
|
33
|
+
Naming/HeredocDelimiterNaming:
|
|
34
|
+
Enabled: false
|
|
35
|
+
|
|
36
|
+
Style/Documentation:
|
|
37
|
+
Enabled: false
|
|
38
|
+
Style/StringLiterals:
|
|
39
|
+
EnforcedStyle: double_quotes
|
data/AGENTS.md
ADDED
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
# swa - AWS CLI (backwards)
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
**swa** is an alternative CLI for AWS that inverts the typical command structure by placing verbs at the end rather than the beginning. The name "swa" is "AWS" spelled backwards, reflecting this design philosophy.
|
|
6
|
+
|
|
7
|
+
**Version:** 0.8.6
|
|
8
|
+
**Repository:** https://github.com/mdub/swa
|
|
9
|
+
**License:** MIT
|
|
10
|
+
**Language:** Ruby
|
|
11
|
+
|
|
12
|
+
### Command structure comparison
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Standard AWS CLI
|
|
16
|
+
aws ec2 terminate-instances --instance-ids i-9336f049
|
|
17
|
+
|
|
18
|
+
# swa
|
|
19
|
+
swa ec2 instance i-9336f049 terminate
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## What swa does
|
|
23
|
+
|
|
24
|
+
swa provides a more intuitive interface to AWS services by organizing commands hierarchically by service, resource type, and then action. It supports:
|
|
25
|
+
|
|
26
|
+
- **Resource inspection** - View details of AWS resources in YAML or JSON format
|
|
27
|
+
- **Resource filtering** - Filter by tags, states, dates, and custom predicates
|
|
28
|
+
- **Batch operations** - List and query collections of resources
|
|
29
|
+
- **JMESPath queries** - Extract specific fields from resource data
|
|
30
|
+
- **Smart resource resolution** - Automatically detect resource types from IDs (e.g., `swa i-123456` → EC2 instance)
|
|
31
|
+
- **Resource actions** - Perform operations like terminate, delete, put, get, etc.
|
|
32
|
+
|
|
33
|
+
### Supported AWS services
|
|
34
|
+
|
|
35
|
+
| Service | Resource types |
|
|
36
|
+
|---------|----------------|
|
|
37
|
+
| **EC2** | Instances, AMIs, Key-pairs, Security Groups, Snapshots, Volumes, Subnets, VPCs |
|
|
38
|
+
| **S3** | Buckets, Objects, Object versions |
|
|
39
|
+
| **IAM** | Users, Roles, Groups, Policies, Instance Profiles |
|
|
40
|
+
| **Glue** | Databases, Tables, Crawlers, Jobs, Job Runs, Partitions |
|
|
41
|
+
| **Athena** | Catalogs, Databases, Query Executions |
|
|
42
|
+
| **KMS** | Keys, Aliases |
|
|
43
|
+
| **CloudFormation** | Stacks, Templates, Parameters, Outputs, Resources |
|
|
44
|
+
| **ELB** | Load Balancers (Classic) |
|
|
45
|
+
| **LakeFormation** | Data Lake Settings, LF-Tags, Permissions, Resources |
|
|
46
|
+
|
|
47
|
+
## Codebase architecture
|
|
48
|
+
|
|
49
|
+
### Directory structure
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
/
|
|
53
|
+
├── exe/
|
|
54
|
+
│ └── swa # Main executable entry point
|
|
55
|
+
├── lib/
|
|
56
|
+
│ └── swa/
|
|
57
|
+
│ ├── cli/ # Command-line interface layer
|
|
58
|
+
│ │ ├── main_command.rb # Top-level command dispatcher
|
|
59
|
+
│ │ ├── base_command.rb # Base class for all commands
|
|
60
|
+
│ │ ├── *_command.rb # Service-specific commands (9 services)
|
|
61
|
+
│ │ ├── collection_behaviour.rb # Mixin for listing resources
|
|
62
|
+
│ │ ├── item_behaviour.rb # Mixin for single resource ops
|
|
63
|
+
│ │ ├── data_output.rb # Output formatting (YAML/JSON)
|
|
64
|
+
│ │ ├── filter_options.rb # AWS filtering
|
|
65
|
+
│ │ ├── tag_filter_options.rb # Tag-based filtering
|
|
66
|
+
│ │ └── selector.rb # Custom filter predicates
|
|
67
|
+
│ ├── athena/ # Athena resource models
|
|
68
|
+
│ ├── cloud_formation/ # CloudFormation resource models
|
|
69
|
+
│ ├── ec2/ # EC2 resource models
|
|
70
|
+
│ ├── elb/ # ELB resource models
|
|
71
|
+
│ ├── glue/ # Glue resource models
|
|
72
|
+
│ ├── iam/ # IAM resource models
|
|
73
|
+
│ ├── kms/ # KMS resource models
|
|
74
|
+
│ ├── lake_formation/ # LakeFormation resource models
|
|
75
|
+
│ ├── s3/ # S3 resource models
|
|
76
|
+
│ ├── resource.rb # Base class for AWS SDK resources
|
|
77
|
+
│ ├── record.rb # Base class for API response records
|
|
78
|
+
│ ├── data_presentation.rb # Display formatting utilities
|
|
79
|
+
│ └── version.rb # Version constant
|
|
80
|
+
└── swa.gemspec # Gem specification
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Key architectural patterns
|
|
84
|
+
|
|
85
|
+
#### 1. Command hierarchy (Clamp framework)
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
MainCommand (Swa::CLI::MainCommand)
|
|
89
|
+
├── BaseCommand (authentication, AWS client setup)
|
|
90
|
+
├── Service Commands (e.g., Ec2Command, S3Command)
|
|
91
|
+
│ ├── Collection Subcommands (e.g., "instances", "buckets")
|
|
92
|
+
│ │ └── Actions: summary, ids, data
|
|
93
|
+
│ └── Item Subcommands (e.g., "instance", "bucket")
|
|
94
|
+
│ └── Actions: summary, data, [resource-specific actions]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- **MainCommand** - Top-level dispatcher, includes smart resource ID prefix matching
|
|
98
|
+
- **BaseCommand** - Shared functionality: AWS authentication, region config, logging
|
|
99
|
+
- **Service Commands** - One per AWS service (9 total)
|
|
100
|
+
- **Mixins:**
|
|
101
|
+
- `CollectionBehaviour` - Provides `summary`, `ids`, `data` subcommands for listings
|
|
102
|
+
- `ItemBehaviour` - Provides `summary`, `data` subcommands for individual items
|
|
103
|
+
|
|
104
|
+
#### 2. Resource wrapping pattern
|
|
105
|
+
|
|
106
|
+
Two base classes wrap AWS SDK objects:
|
|
107
|
+
|
|
108
|
+
**Resource** class (`lib/swa/resource.rb`):
|
|
109
|
+
- Used for AWS SDK resource objects (EC2, S3, IAM, CloudFormation, ELB)
|
|
110
|
+
- Delegates method calls to underlying SDK resource
|
|
111
|
+
- Provides standard interface:
|
|
112
|
+
- `summary()` - One-line display string
|
|
113
|
+
- `id` - Resource identifier
|
|
114
|
+
- `data()` - Full data as hash (for YAML/JSON output)
|
|
115
|
+
|
|
116
|
+
**Record** class (`lib/swa/record.rb`):
|
|
117
|
+
- Used for API response data structures (Glue, Athena, KMS, LakeFormation)
|
|
118
|
+
- Wraps plain Ruby hashes/structs from API responses
|
|
119
|
+
- Same standard interface as Resource
|
|
120
|
+
|
|
121
|
+
Each AWS service has specialized subclasses in its directory (e.g., `Swa::EC2::Instance`, `Swa::S3::Bucket`).
|
|
122
|
+
|
|
123
|
+
#### 3. Filtering and querying
|
|
124
|
+
|
|
125
|
+
Multiple filtering mechanisms work together:
|
|
126
|
+
|
|
127
|
+
- **FilterOptions** - AWS API-level filters (e.g., `--filter name=value`)
|
|
128
|
+
- **TagFilterOptions** - Tag-based filtering (e.g., `--tagged environment=prod`)
|
|
129
|
+
- **Selector** - Custom Ruby predicates for in-memory filtering
|
|
130
|
+
- **Date ranges** - Via Chronic gem for date/time parsing
|
|
131
|
+
- **JMESPath** - Query expressions for extracting specific fields from output
|
|
132
|
+
|
|
133
|
+
#### 4. Output formatting
|
|
134
|
+
|
|
135
|
+
**DataOutput** module provides:
|
|
136
|
+
- YAML output (default)
|
|
137
|
+
- JSON output (`--json` / `-J`)
|
|
138
|
+
- JMESPath query support (as command argument)
|
|
139
|
+
- Pretty-printing with indentation
|
|
140
|
+
- CSV support for certain data types
|
|
141
|
+
|
|
142
|
+
### Core components
|
|
143
|
+
|
|
144
|
+
#### CLI layer (`lib/swa/cli/`)
|
|
145
|
+
|
|
146
|
+
| File | Purpose |
|
|
147
|
+
|------|---------|
|
|
148
|
+
| `main_command.rb` | Top-level command, service dispatch, smart ID prefix matching |
|
|
149
|
+
| `base_command.rb` | AWS authentication, region config, client setup |
|
|
150
|
+
| `athena_command.rb` | Athena catalogs, databases, queries |
|
|
151
|
+
| `cloud_formation_command.rb` | CloudFormation stacks, templates |
|
|
152
|
+
| `ec2_command.rb` | EC2 instances, images, volumes, security groups, etc. |
|
|
153
|
+
| `elb_command.rb` | Elastic Load Balancers |
|
|
154
|
+
| `glue_command.rb` | Glue databases, tables, jobs, crawlers |
|
|
155
|
+
| `iam_command.rb` | IAM users, roles, groups, policies |
|
|
156
|
+
| `kms_command.rb` | KMS keys, aliases |
|
|
157
|
+
| `lake_formation_command.rb` | LakeFormation tags, permissions |
|
|
158
|
+
| `s3_command.rb` | S3 buckets, objects |
|
|
159
|
+
| `collection_behaviour.rb` | Mixin: list resources, filter, output |
|
|
160
|
+
| `item_behaviour.rb` | Mixin: single resource inspection |
|
|
161
|
+
| `data_output.rb` | YAML/JSON formatting, JMESPath |
|
|
162
|
+
| `filter_options.rb` | AWS API filter options |
|
|
163
|
+
| `tag_filter_options.rb` | Tag-based filter options |
|
|
164
|
+
| `selector.rb` | Custom predicate filtering |
|
|
165
|
+
|
|
166
|
+
#### Resource models
|
|
167
|
+
|
|
168
|
+
Each AWS service has a directory with resource model classes:
|
|
169
|
+
|
|
170
|
+
- **EC2** - 9 resource types (Instance, Image, KeyPair, SecurityGroup, Snapshot, Volume, Subnet, Vpc, TaggedResource)
|
|
171
|
+
- **S3** - 6 types (Bucket, Object, ObjectVersion, ObjectListEntry, ObjectSummary, ObjectPrefix)
|
|
172
|
+
- **IAM** - 7 types (User, Role, Group, Policy, RolePolicy, InstanceProfile, Credentials)
|
|
173
|
+
- **Glue** - 8 types (Database, Table, Job, JobRun, JobBookmarkEntry, Crawler, Crawl, Partition)
|
|
174
|
+
- **Athena** - 4 types (Catalog, Database, QueryExecution, WorkGroup)
|
|
175
|
+
- **KMS** - 2 types (Key, Alias)
|
|
176
|
+
- **CloudFormation** - 1 type (Stack)
|
|
177
|
+
- **ELB** - 1 type (LoadBalancer)
|
|
178
|
+
- **LakeFormation** - 4 types (DataLakeSettings, Permission, ResourceInfo, Tag)
|
|
179
|
+
|
|
180
|
+
Each model:
|
|
181
|
+
- Extends `Resource` or `Record`
|
|
182
|
+
- Implements `summary()` for display
|
|
183
|
+
- Exposes attributes via method delegation
|
|
184
|
+
- May implement custom actions (e.g., `terminate`, `delete`, `put`)
|
|
185
|
+
|
|
186
|
+
### Key dependencies
|
|
187
|
+
|
|
188
|
+
```ruby
|
|
189
|
+
# AWS SDK (modular approach)
|
|
190
|
+
aws-sdk-athena, aws-sdk-cloudformation, aws-sdk-ec2,
|
|
191
|
+
aws-sdk-elasticloadbalancing, aws-sdk-glue, aws-sdk-iam,
|
|
192
|
+
aws-sdk-kms, aws-sdk-lakeformation, aws-sdk-s3
|
|
193
|
+
|
|
194
|
+
# CLI framework
|
|
195
|
+
clamp (~> 1.1.0) # Command-line parsing
|
|
196
|
+
|
|
197
|
+
# Data processing
|
|
198
|
+
multi_json # JSON serialization
|
|
199
|
+
jmespath # Query language for JSON
|
|
200
|
+
chronic # Natural language date/time parsing
|
|
201
|
+
ox # XML parsing
|
|
202
|
+
|
|
203
|
+
# Display formatting
|
|
204
|
+
console_logger # Structured logging
|
|
205
|
+
bytesize # Human-readable byte sizes
|
|
206
|
+
|
|
207
|
+
# Utilities
|
|
208
|
+
stackup (~> 1.0.0) # CloudFormation tooling
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## How the codebase hangs together
|
|
212
|
+
|
|
213
|
+
### 1. Command execution flow
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
User runs: swa ec2 instance i-123456 data --json
|
|
217
|
+
↓
|
|
218
|
+
MainCommand.run (lib/swa/cli/main_command.rb)
|
|
219
|
+
↓
|
|
220
|
+
Ec2Command (lib/swa/cli/ec2_command.rb)
|
|
221
|
+
↓
|
|
222
|
+
InstanceCommand (defined in Ec2Command via subcommand DSL)
|
|
223
|
+
↓
|
|
224
|
+
ItemBehaviour#execute (lib/swa/cli/item_behaviour.rb)
|
|
225
|
+
↓
|
|
226
|
+
find_item method (retrieves AWS::EC2::Instance)
|
|
227
|
+
↓
|
|
228
|
+
Wrapped as Swa::EC2::Instance (lib/swa/ec2/instance.rb)
|
|
229
|
+
↓
|
|
230
|
+
DataCommand.execute (outputs data as JSON)
|
|
231
|
+
↓
|
|
232
|
+
Output formatted and printed to stdout
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### 2. Smart prefix matching
|
|
236
|
+
|
|
237
|
+
MainCommand includes logic to detect resource prefixes and route commands automatically:
|
|
238
|
+
|
|
239
|
+
```ruby
|
|
240
|
+
# In lib/swa/cli/main_command.rb
|
|
241
|
+
case parameter
|
|
242
|
+
when /^i-/ then ["ec2", "instance", parameter]
|
|
243
|
+
when /^ami-/ then ["ec2", "image", parameter]
|
|
244
|
+
when /^sg-/ then ["ec2", "security-group", parameter]
|
|
245
|
+
when /^vol-/ then ["ec2", "volume", parameter]
|
|
246
|
+
when /^snap-/ then ["ec2", "snapshot", parameter]
|
|
247
|
+
when /^s3:\/\// then s3_url_command_line(parameter)
|
|
248
|
+
when /^arn:.*:iam:.*:policy\// then ["iam", "policy", parameter]
|
|
249
|
+
# ... etc
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
This allows shortcut commands like:
|
|
253
|
+
```bash
|
|
254
|
+
swa i-123456 data # → swa ec2 instance i-123456 data
|
|
255
|
+
swa sg-789abc data # → swa ec2 security-group sg-789abc data
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### 3. Collection vs. item commands
|
|
259
|
+
|
|
260
|
+
**Collection commands** (plural, e.g., "instances"):
|
|
261
|
+
- List multiple resources
|
|
262
|
+
- Apply filters (tags, state, date ranges, AWS API filters)
|
|
263
|
+
- Support three output modes:
|
|
264
|
+
- `summary` - One-line per resource (default)
|
|
265
|
+
- `ids` - Just resource identifiers
|
|
266
|
+
- `data` - Full YAML/JSON with optional JMESPath
|
|
267
|
+
|
|
268
|
+
**Item commands** (singular, e.g., "instance"):
|
|
269
|
+
- Address a single resource by ID
|
|
270
|
+
- Support inspection (`summary`, `data`)
|
|
271
|
+
- Support resource-specific actions (`terminate`, `delete`, `get`, `put`, etc.)
|
|
272
|
+
|
|
273
|
+
### 4. AWS SDK integration
|
|
274
|
+
|
|
275
|
+
BaseCommand establishes AWS clients:
|
|
276
|
+
```ruby
|
|
277
|
+
def aws_config
|
|
278
|
+
@aws_config ||= {}.tap do |config|
|
|
279
|
+
config[:region] = region if region
|
|
280
|
+
config[:credentials] = aws_credentials if aws_credentials
|
|
281
|
+
# ... other config
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Service commands create AWS SDK clients:
|
|
287
|
+
```ruby
|
|
288
|
+
def ec2
|
|
289
|
+
@ec2 ||= Aws::EC2::Resource.new(aws_config)
|
|
290
|
+
end
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Resource wrappers delegate to SDK objects:
|
|
294
|
+
```ruby
|
|
295
|
+
class Instance < Swa::Resource
|
|
296
|
+
def summary
|
|
297
|
+
[id, image_id, instance_type, state.name, private_ip_address].join(" ")
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### 5. Data presentation
|
|
303
|
+
|
|
304
|
+
Resources implement `data()` method to return hash for serialization:
|
|
305
|
+
```ruby
|
|
306
|
+
def data
|
|
307
|
+
{
|
|
308
|
+
"InstanceId" => id,
|
|
309
|
+
"ImageId" => image_id,
|
|
310
|
+
"InstanceType" => instance_type,
|
|
311
|
+
"State" => state.name,
|
|
312
|
+
# ... etc
|
|
313
|
+
}
|
|
314
|
+
end
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
DataOutput handles formatting:
|
|
318
|
+
- Applies JMESPath query if specified
|
|
319
|
+
- Serializes to YAML (default) or JSON
|
|
320
|
+
- Pretty-prints with proper indentation
|
|
321
|
+
|
|
322
|
+
### 6. Extension points
|
|
323
|
+
|
|
324
|
+
The architecture makes it easy to add new services or resources:
|
|
325
|
+
|
|
326
|
+
1. **Add a new service:**
|
|
327
|
+
- Create `lib/swa/cli/new_service_command.rb`
|
|
328
|
+
- Extend `BaseCommand`
|
|
329
|
+
- Define collection and item subcommands
|
|
330
|
+
- Register in `MainCommand`
|
|
331
|
+
|
|
332
|
+
2. **Add a new resource type:**
|
|
333
|
+
- Create `lib/swa/new_service/new_resource.rb`
|
|
334
|
+
- Extend `Resource` or `Record`
|
|
335
|
+
- Implement `summary()` and optionally `data()`
|
|
336
|
+
- Add command in service command class
|
|
337
|
+
|
|
338
|
+
3. **Add a new action:**
|
|
339
|
+
- Define method in resource class
|
|
340
|
+
- Add subcommand in item command
|
|
341
|
+
- Handle action-specific options
|
|
342
|
+
|
|
343
|
+
## Usage patterns
|
|
344
|
+
|
|
345
|
+
### Basic inspection
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
# List resources
|
|
349
|
+
swa ec2 instances summary
|
|
350
|
+
swa s3 buckets
|
|
351
|
+
swa iam users
|
|
352
|
+
|
|
353
|
+
# Inspect single resource
|
|
354
|
+
swa ec2 instance i-123456 data
|
|
355
|
+
swa s3 bucket my-bucket data
|
|
356
|
+
swa iam user alice data --json
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Filtering
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
# By tag
|
|
363
|
+
swa ec2 instances --tagged environment=prod
|
|
364
|
+
|
|
365
|
+
# By state
|
|
366
|
+
swa ec2 instances --state running
|
|
367
|
+
|
|
368
|
+
# By AWS API filter
|
|
369
|
+
swa ec2 instances --filter availability-zone=us-east-1a
|
|
370
|
+
|
|
371
|
+
# By date range
|
|
372
|
+
swa ec2 snapshots --since "last week"
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Querying with JMESPath
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
# Extract specific fields
|
|
379
|
+
swa ec2 instances data '[].{Id:InstanceId,Type:InstanceType,State:State.Name}'
|
|
380
|
+
|
|
381
|
+
# Get just IPs
|
|
382
|
+
swa ec2 instances data '[].PrivateIpAddress'
|
|
383
|
+
|
|
384
|
+
# Complex query
|
|
385
|
+
swa s3 buckets data '[?CreationDate > `2024-01-01`].Name'
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Resource actions
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
# EC2
|
|
392
|
+
swa ec2 instance i-123456 terminate
|
|
393
|
+
|
|
394
|
+
# S3
|
|
395
|
+
swa s3 bucket my-bucket object mykey get > file.txt
|
|
396
|
+
echo "content" | swa s3 bucket my-bucket object mykey put
|
|
397
|
+
|
|
398
|
+
# IAM
|
|
399
|
+
swa iam role my-role assume --session-name mysession
|
|
400
|
+
|
|
401
|
+
# Glue
|
|
402
|
+
swa glue job my-job start
|
|
403
|
+
swa glue crawler my-crawler start
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Complex operations
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
# Athena query execution
|
|
410
|
+
swa athena query "SELECT * FROM mytable" -D mydb -O s3://bucket/path/
|
|
411
|
+
|
|
412
|
+
# Glue database and table addressing
|
|
413
|
+
swa glue database mydb table mytable data
|
|
414
|
+
|
|
415
|
+
# LakeFormation permissions
|
|
416
|
+
swa glue database mydb table mytable lf-permissions
|
|
417
|
+
|
|
418
|
+
# CloudFormation stack inspection
|
|
419
|
+
swa cf stack my-stack template
|
|
420
|
+
swa cf stack my-stack outputs
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Smart shortcuts
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
# Automatic resource type detection
|
|
427
|
+
swa i-123456 data # EC2 instance
|
|
428
|
+
swa ami-789abc data # EC2 AMI
|
|
429
|
+
swa sg-456def data # EC2 security group
|
|
430
|
+
swa s3://my-bucket/path/file get # S3 object
|
|
431
|
+
swa arn:aws:iam::123:policy/MyPolicy # IAM policy
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## Development focus areas
|
|
435
|
+
|
|
436
|
+
Based on recent commit history:
|
|
437
|
+
- Glue and LakeFormation integration (active development)
|
|
438
|
+
- ARN-based resource addressing
|
|
439
|
+
- Enhanced filtering and pattern matching
|
|
440
|
+
- Catalog specification for Glue resources
|
|
441
|
+
|
|
442
|
+
The tool appears to be particularly focused on AWS data services (Glue, Athena, LakeFormation) while maintaining broad coverage of core AWS services.
|
|
443
|
+
|
|
444
|
+
## Issue Tracking with bd (beads)
|
|
445
|
+
|
|
446
|
+
**IMPORTANT**: This project uses **bd (beads)** for ALL issue tracking. Do NOT use markdown TODOs, task lists, or other tracking methods.
|
|
447
|
+
|
|
448
|
+
### Why bd?
|
|
449
|
+
|
|
450
|
+
- Dependency-aware: Track blockers and relationships between issues
|
|
451
|
+
- Git-friendly: Auto-syncs to JSONL for version control
|
|
452
|
+
- Agent-optimized: JSON output, ready work detection, discovered-from links
|
|
453
|
+
- Prevents duplicate tracking systems and confusion
|
|
454
|
+
|
|
455
|
+
### Quick Start
|
|
456
|
+
|
|
457
|
+
**Check for ready work:**
|
|
458
|
+
```bash
|
|
459
|
+
bd ready --json
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
**Create new issues:**
|
|
463
|
+
```bash
|
|
464
|
+
bd create "Issue title" -t bug|feature|task -p 0-4 --json
|
|
465
|
+
bd create "Issue title" -p 1 --deps discovered-from:bd-123 --json
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**Claim and update:**
|
|
469
|
+
```bash
|
|
470
|
+
bd update bd-42 --status in_progress --json
|
|
471
|
+
bd update bd-42 --priority 1 --json
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
**Complete work:**
|
|
475
|
+
```bash
|
|
476
|
+
bd close bd-42 --reason "Completed" --json
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### Issue Types
|
|
480
|
+
|
|
481
|
+
- `bug` - Something broken
|
|
482
|
+
- `feature` - New functionality
|
|
483
|
+
- `task` - Work item (tests, docs, refactoring)
|
|
484
|
+
- `epic` - Large feature with subtasks
|
|
485
|
+
- `chore` - Maintenance (dependencies, tooling)
|
|
486
|
+
|
|
487
|
+
### Priorities
|
|
488
|
+
|
|
489
|
+
- `0` - Critical (security, data loss, broken builds)
|
|
490
|
+
- `1` - High (major features, important bugs)
|
|
491
|
+
- `2` - Medium (default, nice-to-have)
|
|
492
|
+
- `3` - Low (polish, optimization)
|
|
493
|
+
- `4` - Backlog (future ideas)
|
|
494
|
+
|
|
495
|
+
### Workflow for AI Agents
|
|
496
|
+
|
|
497
|
+
1. **Check ready work**: `bd ready` shows unblocked issues
|
|
498
|
+
2. **Claim your task**: `bd update <id> --status in_progress`
|
|
499
|
+
3. **Work on it**: Implement, test, document
|
|
500
|
+
4. **Discover new work?** Create linked issue:
|
|
501
|
+
- `bd create "Found bug" -p 1 --deps discovered-from:<parent-id>`
|
|
502
|
+
5. **Complete**: `bd close <id> --reason "Done"`
|
|
503
|
+
|
|
504
|
+
### Auto-Sync
|
|
505
|
+
|
|
506
|
+
bd automatically syncs with git:
|
|
507
|
+
- Exports to `.beads/issues.jsonl` after changes (5s debounce)
|
|
508
|
+
- Imports from JSONL when newer (e.g., after `git pull`)
|
|
509
|
+
- No manual export/import needed!
|
|
510
|
+
|
|
511
|
+
### MCP Server (Recommended)
|
|
512
|
+
|
|
513
|
+
If using Claude or MCP-compatible clients, install the beads MCP server:
|
|
514
|
+
|
|
515
|
+
```bash
|
|
516
|
+
pip install beads-mcp
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Add to MCP config (e.g., `~/.config/claude/config.json`):
|
|
520
|
+
```json
|
|
521
|
+
{
|
|
522
|
+
"beads": {
|
|
523
|
+
"command": "beads-mcp",
|
|
524
|
+
"args": []
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
Then use `mcp__beads__*` functions instead of CLI commands.
|
|
530
|
+
|
|
531
|
+
### Important Rules
|
|
532
|
+
|
|
533
|
+
- ✅ Use bd for ALL task tracking
|
|
534
|
+
- ✅ Always use `--json` flag for programmatic use
|
|
535
|
+
- ✅ Link discovered work with `discovered-from` dependencies
|
|
536
|
+
- ✅ Check `bd ready` before asking "what should I work on?"
|
|
537
|
+
- ❌ Do NOT create markdown TODO lists
|
|
538
|
+
- ❌ Do NOT use external issue trackers
|
|
539
|
+
- ❌ Do NOT duplicate tracking systems
|
|
540
|
+
|
|
541
|
+
For more details, see README.md and QUICKSTART.md.
|
data/CLAUDE.md
ADDED
data/Gemfile
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
2
4
|
|
|
3
5
|
# Specify your gem's dependencies in swa.gemspec
|
|
4
6
|
gemspec
|
|
7
|
+
|
|
8
|
+
group :development do
|
|
9
|
+
gem "bundler", "~> 2.1"
|
|
10
|
+
gem "rake", "~> 12.0"
|
|
11
|
+
gem "rubocop", "~> 1.0"
|
|
12
|
+
end
|
data/README.md
CHANGED
|
@@ -82,11 +82,6 @@ SWA is packaged as a Ruby gem, and can be installed with:
|
|
|
82
82
|
|
|
83
83
|
gem install swa
|
|
84
84
|
|
|
85
|
-
On a Mac, I recommend [brew-gem](https://github.com/sportngin/brew-gem) for easy system-wide installation:
|
|
86
|
-
|
|
87
|
-
brew install brew-gem
|
|
88
|
-
brew gem install swa
|
|
89
|
-
|
|
90
85
|
## Contributing
|
|
91
86
|
|
|
92
87
|
Bug reports and pull requests are welcome on GitHub at https://github.com/mdub/swa.
|
data/Rakefile
CHANGED
data/bin/console
CHANGED