Skip to content

feat: sync the rds cluster resource#62

Merged
dacbd merged 1 commit intomainfrom
dacbd/rds-cluster-scan
Mar 19, 2026
Merged

feat: sync the rds cluster resource#62
dacbd merged 1 commit intomainfrom
dacbd/rds-cluster-scan

Conversation

@dacbd
Copy link
Collaborator

@dacbd dacbd commented Mar 19, 2026

the intern claude cooked this up for me. In general for aws actions we should probably be triggering off of data on the cluster and not individual instances anyway.

Summary by CodeRabbit

  • New Features
    • Extended AWS RDS synchronization to discover database clusters alongside instances, including metadata for engine type, status, endpoints, and other cluster-specific configurations.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 19, 2026

📝 Walkthrough

Walkthrough

The PR extends RDS synchronization to process DB clusters in addition to existing instance enumeration. New functions paginate AWS cluster APIs, convert cluster objects to resource representations, and extract cluster-specific metadata including engine, endpoints, and configuration details.

Changes

Cohort / File(s) Summary
RDS Cluster Support
cmd/ctrlc/root/sync/aws/rds/rds.go
Extended runSync to invoke processClusters, added cluster pagination logic via DescribeDBClusters, implemented processCluster to construct AmazonRelationalDatabaseCluster resources, and added buildClusterMetadata to extract cluster-level details (engine, endpoints, storage, KMS, multiAZ, tags, etc.)

Sequence Diagram(s)

sequenceDiagram
    participant Sync as Sync Orchestrator
    participant RDS as AWS RDS API
    participant Converter as Cluster Converter
    participant Meta as Metadata Builder
    participant Resources as Resource List

    Sync->>RDS: DescribeDBClusters (paginated)
    RDS-->>Sync: DBCluster list
    
    loop For each cluster
        Sync->>Converter: processCluster(cluster, region)
        Converter->>Meta: buildClusterMetadata(cluster)
        Meta-->>Converter: metadata map (engine, endpoints, etc.)
        Converter->>Converter: construct AmazonRelationalDatabaseCluster
        Converter-->>Sync: cluster resource object
    end
    
    Sync->>Resources: append cluster resources
    Resources-->>Sync: updated resource list
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Hark! The clusters now take flight,
Where RDS brings them into light,
With engines purring, endpoints neat,
Metadata harvested—review complete!
Hop onward, to sync more delight! 🌟

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: sync the rds cluster resource' directly and clearly summarizes the main change: adding RDS cluster synchronization functionality to the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dacbd/rds-cluster-scan
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can use OpenGrep to find security vulnerabilities and bugs across 17+ programming languages.

OpenGrep is compatible with Semgrep configurations. Add an opengrep.yml or semgrep.yml configuration file to your project to enable OpenGrep analysis.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
cmd/ctrlc/root/sync/aws/rds/rds.go (4)

94-100: Inconsistent error handling between instances and clusters.

When processInstances fails (lines 86-92), the error is appended to syncErrors and the goroutine returns early. When processClusters fails, the error is only logged and execution continues. If this is intentional (clusters are supplementary), consider adding a comment explaining the design choice. If not, align the error handling:

 				// List and process clusters for this region
 				clusterResources, err := processClusters(ctx, rdsClient, regionName)
 				if err != nil {
 					log.Error("Failed to process clusters", "region", regionName, "error", err)
+					// Note: cluster errors are non-fatal; we still return instance resources
 				} else {
 					resources = append(resources, clusterResources...)
 				}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/ctrlc/root/sync/aws/rds/rds.go` around lines 94 - 100, The error handling
for processClusters is inconsistent with processInstances: processInstances adds
the error to syncErrors and returns from the goroutine, but processClusters only
logs the error and continues; update the processClusters error branch (the block
that calls processClusters(ctx, rdsClient, regionName)) to mirror
processInstances by appending the error to syncErrors and returning from the
goroutine, or if clusters are intentionally non-fatal, add a clear comment
explaining that design choice next to the processClusters call; reference
processInstances, processClusters, and syncErrors when making the change so the
behavior is consistent and discoverable.

268-275: Potential nil pointer dereference on DBClusterIdentifier.

At line 271, *cluster.DBClusterIdentifier is dereferenced without a nil check. While AWS typically guarantees this field, a defensive check would prevent a panic in edge cases. Note: The existing processInstances has the same pattern at line 177, so this is consistent with the codebase.

🛡️ Suggested defensive check
 		for _, cluster := range resp.DBClusters {
+			if cluster.DBClusterIdentifier == nil {
+				log.Warn("Skipping cluster with nil identifier")
+				continue
+			}
 			resource, err := processCluster(&cluster, region)
 			if err != nil {
 				log.Error("Failed to process RDS cluster", "identifier", *cluster.DBClusterIdentifier, "error", err)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/ctrlc/root/sync/aws/rds/rds.go` around lines 268 - 275, The loop over
resp.DBClusters dereferences *cluster.DBClusterIdentifier without a nil check
which can panic; update the loop in the function that iterates resp.DBClusters
(the block calling processCluster(&cluster, region)) to defensively check
cluster.DBClusterIdentifier for nil before using it in log.Error (or use a safe
fallback identifier string), and only include the pointer value when non-nil;
keep the call to processCluster(&cluster, region) and append behavior unchanged
for valid clusters.

423-427: Tag injection without key sanitization.

User-controlled AWS tag keys are directly interpolated into metadata keys at line 425. While AWS tag key restrictions are fairly strict, consider validating or sanitizing tag keys to prevent potential issues with special characters that might affect downstream metadata consumers.

🛡️ Example sanitization approach
 	for _, tag := range cluster.TagList {
 		if tag.Key != nil && tag.Value != nil {
-			metadata[fmt.Sprintf("tags/%s", *tag.Key)] = *tag.Value
+			// AWS tag keys can contain unicode, +, -, =, ., _, :, /, @
+			// Sanitize if downstream systems have stricter requirements
+			sanitizedKey := strings.ReplaceAll(*tag.Key, "/", "_")
+			metadata[fmt.Sprintf("tags/%s", sanitizedKey)] = *tag.Value
 		}
 	}

Note: The existing buildInstanceMetadata function (line 634-637) has the same pattern, so this is consistent with the codebase.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/ctrlc/root/sync/aws/rds/rds.go` around lines 423 - 427, The loop that
injects AWS tag keys into metadata (iterating cluster.TagList and setting
metadata[fmt.Sprintf("tags/%s", *tag.Key)]) uses raw tag keys and should
sanitize/validate them first to avoid introducing special characters into
metadata keys; update the code in the function that handles cluster tags (the
for-loop over cluster.TagList) to normalize tag keys (e.g., trim whitespace,
replace or remove characters outside a safe whitelist like alphanumerics,
dashes, underscores or percent-encode/hex-encode unsafe characters) and fall
back to a deterministic safe name when a key becomes empty, then use the
sanitized key in fmt.Sprintf("tags/%s", sanitizedKey); apply the same
sanitization utility to buildInstanceMetadata to keep behavior consistent.

298-306: ARN fallback construction may produce invalid format.

The fallback ARN at line 302 uses format arn:aws:rds:%s::%s which omits the account ID and resource type prefix. A proper cluster ARN format is arn:aws:rds:region:account-id:cluster:identifier. This matches the existing pattern in processInstance (line 211), so it's consistent but may cause issues with downstream systems expecting valid ARNs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/ctrlc/root/sync/aws/rds/rds.go` around lines 298 - 306, The fallback ARN
construction for identifier currently uses "arn:aws:rds:%s::%s" which omits
account ID and "cluster:" resource type; update the logic in the block that
reads cluster.DBClusterArn / cluster.DBClusterIdentifier (the identifier
variable) to build a valid ARN using the same pattern as processInstance (i.e.,
"arn:aws:rds:%s:%s:cluster:%s"), obtaining the AWS account ID via the existing
account lookup (reuse the code/path that supplies the account ID or call STS
GetCallerIdentity if no helper exists) and then format the ARN with region,
accountID and cluster identifier so downstream systems receive a correct cluster
ARN.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/ctrlc/root/sync/aws/rds/rds.go`:
- Around line 310-319: The code dereferences cluster fields unsafely and stores
a *bool pointer instead of a bool; before calling getNormalizedDBType and
building awsClusterConfig, defensively check cluster.Engine,
cluster.EngineVersion, and cluster.Status for nil and use safe defaults (e.g.,
empty string) when nil, and dereference cluster.MultiAZ into a bool (default
false) instead of storing the pointer; update references around
getNormalizedDBType, the awsClusterConfig map, and any usages of
cluster.Engine/EngineVersion/Status/MultiAZ to use these safe, dereferenced
values.

---

Nitpick comments:
In `@cmd/ctrlc/root/sync/aws/rds/rds.go`:
- Around line 94-100: The error handling for processClusters is inconsistent
with processInstances: processInstances adds the error to syncErrors and returns
from the goroutine, but processClusters only logs the error and continues;
update the processClusters error branch (the block that calls
processClusters(ctx, rdsClient, regionName)) to mirror processInstances by
appending the error to syncErrors and returning from the goroutine, or if
clusters are intentionally non-fatal, add a clear comment explaining that design
choice next to the processClusters call; reference processInstances,
processClusters, and syncErrors when making the change so the behavior is
consistent and discoverable.
- Around line 268-275: The loop over resp.DBClusters dereferences
*cluster.DBClusterIdentifier without a nil check which can panic; update the
loop in the function that iterates resp.DBClusters (the block calling
processCluster(&cluster, region)) to defensively check
cluster.DBClusterIdentifier for nil before using it in log.Error (or use a safe
fallback identifier string), and only include the pointer value when non-nil;
keep the call to processCluster(&cluster, region) and append behavior unchanged
for valid clusters.
- Around line 423-427: The loop that injects AWS tag keys into metadata
(iterating cluster.TagList and setting metadata[fmt.Sprintf("tags/%s",
*tag.Key)]) uses raw tag keys and should sanitize/validate them first to avoid
introducing special characters into metadata keys; update the code in the
function that handles cluster tags (the for-loop over cluster.TagList) to
normalize tag keys (e.g., trim whitespace, replace or remove characters outside
a safe whitelist like alphanumerics, dashes, underscores or
percent-encode/hex-encode unsafe characters) and fall back to a deterministic
safe name when a key becomes empty, then use the sanitized key in
fmt.Sprintf("tags/%s", sanitizedKey); apply the same sanitization utility to
buildInstanceMetadata to keep behavior consistent.
- Around line 298-306: The fallback ARN construction for identifier currently
uses "arn:aws:rds:%s::%s" which omits account ID and "cluster:" resource type;
update the logic in the block that reads cluster.DBClusterArn /
cluster.DBClusterIdentifier (the identifier variable) to build a valid ARN using
the same pattern as processInstance (i.e., "arn:aws:rds:%s:%s:cluster:%s"),
obtaining the AWS account ID via the existing account lookup (reuse the
code/path that supplies the account ID or call STS GetCallerIdentity if no
helper exists) and then format the ARN with region, accountID and cluster
identifier so downstream systems receive a correct cluster ARN.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8236ada9-7d32-49c6-9d87-def4ad0fb6af

📥 Commits

Reviewing files that changed from the base of the PR and between c8802fc and 6fe6c37.

📒 Files selected for processing (1)
  • cmd/ctrlc/root/sync/aws/rds/rds.go

Comment on lines +310 to +319
dbType := getNormalizedDBType(*cluster.Engine)

awsClusterConfig := map[string]any{
"engine": *cluster.Engine,
"engineVersion": *cluster.EngineVersion,
"region": region,
"status": *cluster.Status,
"dbType": dbType,
"multiAZ": cluster.MultiAZ,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential nil pointer dereference on cluster fields.

Several fields are dereferenced without nil checks: Engine (line 310, 313), EngineVersion (line 314), Status (line 316). Additionally, cluster.MultiAZ at line 318 is assigned directly to the config map without dereferencing, but MultiAZ is a *bool. This will store the pointer itself rather than the boolean value, leading to inconsistent serialization.

🐛 Proposed fix for MultiAZ handling
 	awsClusterConfig := map[string]any{
 		"engine":        *cluster.Engine,
 		"engineVersion": *cluster.EngineVersion,
 		"region":        region,
 		"status":        *cluster.Status,
 		"dbType":        dbType,
-		"multiAZ":       cluster.MultiAZ,
+		"multiAZ":       cluster.MultiAZ != nil && *cluster.MultiAZ,
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
dbType := getNormalizedDBType(*cluster.Engine)
awsClusterConfig := map[string]any{
"engine": *cluster.Engine,
"engineVersion": *cluster.EngineVersion,
"region": region,
"status": *cluster.Status,
"dbType": dbType,
"multiAZ": cluster.MultiAZ,
}
dbType := getNormalizedDBType(*cluster.Engine)
awsClusterConfig := map[string]any{
"engine": *cluster.Engine,
"engineVersion": *cluster.EngineVersion,
"region": region,
"status": *cluster.Status,
"dbType": dbType,
"multiAZ": cluster.MultiAZ != nil && *cluster.MultiAZ,
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/ctrlc/root/sync/aws/rds/rds.go` around lines 310 - 319, The code
dereferences cluster fields unsafely and stores a *bool pointer instead of a
bool; before calling getNormalizedDBType and building awsClusterConfig,
defensively check cluster.Engine, cluster.EngineVersion, and cluster.Status for
nil and use safe defaults (e.g., empty string) when nil, and dereference
cluster.MultiAZ into a bool (default false) instead of storing the pointer;
update references around getNormalizedDBType, the awsClusterConfig map, and any
usages of cluster.Engine/EngineVersion/Status/MultiAZ to use these safe,
dereferenced values.

@dacbd dacbd merged commit 186efd6 into main Mar 19, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant