Skip to content

fix(purchases): mask idempotency token in EC2 RI re-drive log (closes #656)#855

Open
cristim wants to merge 1 commit into
feat/multicloud-web-frontendfrom
fix/656-wave16
Open

fix(purchases): mask idempotency token in EC2 RI re-drive log (closes #656)#855
cristim wants to merge 1 commit into
feat/multicloud-web-frontendfrom
fix/656-wave16

Conversation

@cristim
Copy link
Copy Markdown
Member

@cristim cristim commented May 30, 2026

Summary

  • Wraps opts.IdempotencyToken with common.MaskToken in the EC2 RI idempotency-guard skip log (providers/aws/services/ec2/client.go:137), bringing EC2 in line with the five sibling executors (RDS, ElastiCache, MemoryDB, OpenSearch, Redshift) fixed in PR feat(purchases): make AWS RDS/ElastiCache/MemoryDB/OpenSearch/Redshift idempotent (refs #641) #652.
  • No import changes needed -- pkg/common is already imported.
  • Adds TestPurchaseCommitment_IdempotencySkipLogMasked asserting the re-drive path returns success and that MaskToken produces the <first-8>... shape, not the raw 64-char token.

Test plan

  • go build ./... clean
  • go test github.com/LeanerCloud/CUDly/providers/aws/services/ec2/... -- 40 tests pass (39 before + 1 new)
  • Audited all 6 AWS service executors: RDS, ElastiCache, MemoryDB, OpenSearch, Redshift already use MaskToken; SavingsPlans passes token as ClientToken with no skip log

Summary by CodeRabbit

Bug Fixes

  • Sensitive idempotency token values in EC2 purchase commitment logs are now masked to prevent exposure of authentication credentials in plaintext, significantly improving security posture while preserving comprehensive operational logging and audit trail capabilities

Tests

  • Added test case verifying correct token masking behavior in EC2 purchase commitment operations when handling idempotency request scenarios and log verification

Review Change Stack

…656)

Wrap opts.IdempotencyToken with common.MaskToken in the EC2 RI
idempotency-guard skip log, matching the treatment applied to RDS,
ElastiCache, MemoryDB, OpenSearch, and Redshift in PR #652. Adds a
test asserting the re-drive path emits the first-8-chars+"..." form.
@cristim cristim added triaged Item has been triaged priority/p3 Polish / idea / may never ship severity/low Minor harm urgency/eventually No deadline impact/internal Team-internal only effort/xs Trivial / one-liner type/security Security finding labels May 30, 2026
@cristim
Copy link
Copy Markdown
Member Author

cristim commented May 30, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 30, 2026

📝 Walkthrough

Walkthrough

PurchaseCommitment now masks idempotency tokens in logs using common.MaskToken(...) instead of logging raw token values when a purchase is skipped due to an already-existing commitment. A new test validates the masking behavior and verifies the idempotency re-drive path.

Changes

Idempotency Token Masking

Layer / File(s) Summary
Token masking in PurchaseCommitment
providers/aws/services/ec2/client.go
The idempotency token "already exists; skipping purchase" log message now masks the provided token value using common.MaskToken(...) instead of logging the raw opts.IdempotencyToken.
Test for idempotency token masking
providers/aws/services/ec2/client_test.go
New test TestPurchaseCommitment_IdempotencySkipLogMasked verifies the idempotency re-drive path: mocks DescribeReservedInstances to return an existing RI tagged with the idempotency token, calls PurchaseCommitment with the token, asserts success with the existing commitment ID, and validates that common.MaskToken(token) produces the expected masked format and differs from the raw token.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related issues

Possibly related PRs

  • LeanerCloud/CUDly#666: Both PRs update PurchaseCommitment idempotency handling to add/verify common.MaskToken(...)-based masked-token logging on the token re-drive/ALREADY_EXISTS path.
  • LeanerCloud/CUDly#638: This PR builds on the EC2 idempotency/dedupe behavior in PurchaseCommitment by masking the IdempotencyToken in logs and adding test coverage.

Suggested labels

priority/p2, severity/medium, effort/s, type/bug

Poem

🐰 A token once logged in plain sight,
Now masked with a rabbit's delight—
Eight chars plus "..." conceals the key,
While tests guard its secrecy.
Security hops, one line at a time! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: masking an idempotency token in EC2 RI logs. It is concise, specific, and directly reflects the primary purpose of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 fix/656-wave16

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 30, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
providers/aws/services/ec2/client_test.go (1)

712-715: 🏗️ Heavy lift

Test does not actually verify the skip-log line masks the token.

Lines 712-715 assert common.MaskToken(token) directly, which only exercises the standalone helper (already covered by tokens_test.go). The production change at client.go:137 is not observed here — if someone reverted that line to log the raw opts.IdempotencyToken, this test would still pass. To guard the regression this PR fixes, capture log output and assert the raw 64-char token never appears while the masked prefix does. Note that doing so requires redirecting the global log writer, which conflicts with t.Parallel(), so this test would need to drop parallelism.

♻️ Sketch: capture log output to assert masking on the real path
func TestPurchaseCommitment_IdempotencySkipLogMasked(t *testing.T) {
	// no t.Parallel(): we redirect the global log writer below
	var buf bytes.Buffer
	log.SetOutput(&buf)
	t.Cleanup(func() { log.SetOutput(os.Stderr) })

	// ... existing mock/setup/PurchaseCommitment call ...

	out := buf.String()
	assert.NotContains(t, out, token, "raw idempotency token must not be logged")
	assert.Contains(t, out, token[:8]+"...", "skip log must contain the masked token")
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@providers/aws/services/ec2/client_test.go` around lines 712 - 715, The test
currently only calls common.MaskToken(token) but doesn't verify the actual
logging path in PurchaseCommitment masks opts.IdempotencyToken; update the test
(e.g., TestPurchaseCommitment_IdempotencySkipLogMasked) to stop using
t.Parallel(), redirect the global log output with log.SetOutput to a
bytes.Buffer (and restore it in t.Cleanup), call the real PurchaseCommitment
path that triggers the skip-log, then assert the buffer does NOT contain the raw
64-char token and DOES contain common.MaskToken(token) or token[:8]+"..." to
ensure the production log uses the masked form rather than the raw
opts.IdempotencyToken.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@providers/aws/services/ec2/client_test.go`:
- Around line 712-715: The test currently only calls common.MaskToken(token) but
doesn't verify the actual logging path in PurchaseCommitment masks
opts.IdempotencyToken; update the test (e.g.,
TestPurchaseCommitment_IdempotencySkipLogMasked) to stop using t.Parallel(),
redirect the global log output with log.SetOutput to a bytes.Buffer (and restore
it in t.Cleanup), call the real PurchaseCommitment path that triggers the
skip-log, then assert the buffer does NOT contain the raw 64-char token and DOES
contain common.MaskToken(token) or token[:8]+"..." to ensure the production log
uses the masked form rather than the raw opts.IdempotencyToken.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ebcb5e45-8b14-4ee1-907a-8db641f26f7c

📥 Commits

Reviewing files that changed from the base of the PR and between 4956d66 and 64128ee.

📒 Files selected for processing (2)
  • providers/aws/services/ec2/client.go
  • providers/aws/services/ec2/client_test.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/xs Trivial / one-liner impact/internal Team-internal only priority/p3 Polish / idea / may never ship severity/low Minor harm triaged Item has been triaged type/security Security finding urgency/eventually No deadline

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant