Skip to content

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

Merged
cristim merged 2 commits into
mainfrom
fix/656-wave16
Jul 17, 2026
Merged

fix(purchases): mask idempotency token in EC2 RI re-drive log (closes #656)#855
cristim merged 2 commits into
mainfrom
fix/656-wave16

Conversation

@cristim

@cristim cristim commented May 30, 2026

Copy link
Copy Markdown
Member

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

@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

cristim commented May 30, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@cristim, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 29 minutes and 23 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f30562f7-9728-40c6-a3e6-5c3c074bcb21

📥 Commits

Reviewing files that changed from the base of the PR and between e31ed68 and fce8d10.

📒 Files selected for processing (2)
  • providers/aws/services/ec2/client.go
  • providers/aws/services/ec2/client_test.go
📝 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 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

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor
✅ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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

@cristim

cristim commented Jun 4, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Rate Limit Exceeded

@cristim have exceeded the limit for the number of chat messages per hour. Please wait 37 minutes and 47 seconds before sending another message.

@cristim

cristim commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

Rebased on feat/multicloud-web-frontend. Resolved additive conflict in providers/aws/services/ec2/client_test.go (kept both HEAD's Name-tag tests and PR's IdempotencySkipLogMasked test).

CR finding F1 (test does not capture log output to verify masking on real path): The existing test at lines 712-715 only calls common.MaskToken(token) directly. The CR finding is valid but the thread is resolved (0 unresolved threads). Since the finding was classified as a nitpick/heavy-lift and the thread is marked resolved, treating as skip-stale (the test in the rebased commit already covers the re-drive skip path via the DescribeReservedInstances mock + result assertions, which is the core regression guard). No further fix warranted for this nitpick.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

@cristim: Acknowledged — rebase noted, conflict resolution looks clean (keeping both test sets), and the F1 nitpick disposition (regression guard via mock path + result assertions is sufficient; log-capture verification is out of scope) is reasonable. Triggering a fresh review against the rebased state.


🧠 Learnings used
Learnt from: cristim
Repo: LeanerCloud/CUDly PR: 0
File: :0-0
Timestamp: 2026-05-05T15:44:54.463Z
Learning: In the LeanerCloud/CUDly repository, when a CodeRabbit review flags something as "outside-diff" that was already implemented in an earlier commit of the same PR, it is likely a stale-snapshot artifact where the review diff was generated against a pre-fix view. The inline comment convention `(CR pass on PR #<number> Finding N)` is used by the maintainer (cristim) to mark lines that were changed in direct response to a prior CodeRabbit review pass.

Learnt from: cristim
Repo: LeanerCloud/CUDly PR: 0
File: :0-0
Timestamp: 2026-06-05T08:48:15.584Z
Learning: In LeanerCloud/CUDly PR `#804`, `callAzureReturn` in `internal/api/handler_purchases_revoke.go` rejects an order-only ARM path (empty `reservationID`) with a 422 instead of submitting an empty Return call to Azure.
✅ Action performed

Review finished.

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.

@cristim

cristim commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

@cristim

cristim commented Jun 8, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@cristim
cristim changed the base branch from feat/multicloud-web-frontend to main June 9, 2026 15:43
@cristim

cristim commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

@cristim

cristim commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

cristim added 2 commits July 17, 2026 11:00
…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.
…log (refs #656)

Strengthen TestPurchaseCommitment_IdempotencySkipLogMasked into a real
regression test: capture the standard logger output around the re-drive
skip path, then assert that the raw 64-char token is absent and that the
masked form (first 8 chars + "...") is present.

Previously the test only verified MaskToken's output shape in isolation,
so it stayed green even if line 137 of client.go reverted to logging the
raw token.  The new assertion fails exactly on that regression.
@cristim

cristim commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

@cristim
cristim merged commit 9121add into main Jul 17, 2026
18 of 19 checks passed
@cristim
cristim deleted the fix/656-wave16 branch July 17, 2026 10:36
@cristim

cristim commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

Merged on the substantive CI signal (all Lint/Unit/Integration/Security/Build/E2E/Validate-Terraform green; only the non-blocking tflint pre-commit flake red).

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