Repository navigation
Conversation
…/GCP (closes #305) Adds enable_archera = false tfvars flag to each cloud environment. When flipped to true, each cloud conditionally creates: - AWS: cross-account IAM role (cudly-archera-integration) with least- privilege Cost Explorer read + RI/SP purchase policy - Azure: custom RBAC role (CUDly Archera Integration) with cost read + reservation purchase actions, assigned to Archera's service principal - GCP: custom project IAM role (cudlyArcheraIntegration) with billing read + CUD purchase permissions, granted to Archera's service account All permission lists are clearly marked PROVISIONAL — they must be confirmed against Archera's integration docs before any environment sets enable_archera = true. TODO(@cristim) comments in archera.tf per cloud call this out explicitly. Per the bootstrap-vs-runtime IAM split: Archera is a runtime integration (cost telemetry reads + commitment purchases during normal operation), so archera.tf lives in the main environment alongside compute.tf, NOT in ci-cd-permissions/. README addendums added to all three cloud envs. terraform fmt and terraform validate pass for all three environments with the flag both on and off.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
terraform/environments/azure/archera.tf (1)
55-59: ⚡ Quick winSeparate purchase capability behind a second explicit flag.
enable_archeracurrently enables both telemetry read and purchase write. A dedicatedenable_archera_purchase_actions(defaultfalse) reduces accidental financial writes during initial rollout.💡 Proposed refactor
resource "azurerm_role_definition" "archera_integration" { @@ permissions { - actions = [ + actions = concat([ # ── Read-only: Cost Management ────────────────────────────────────── @@ # ── Read-only: Reserved Instances ───────────────────────────────── @@ - # ── Purchase-execution: Reserved Instances ──────────────────────── - # TODO(`@cristim`): enable only after confirming approval workflow with - # Archera (i.e. Archera requires customer approval before purchases). - "Microsoft.Capacity/reservationOrders/write", - ] + ], var.enable_archera_purchase_actions ? [ + "Microsoft.Capacity/reservationOrders/write", + ] : []) not_actions = [] }# variables.tf (add) variable "enable_archera_purchase_actions" { description = "Allow Archera purchase actions (RI/SP). Keep false until approval workflow is confirmed." type = bool default = false }🤖 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 `@terraform/environments/azure/archera.tf` around lines 55 - 59, Current setup ties telemetry and purchase permissions to a single flag (enable_archera); add a new variable enable_archera_purchase_actions (bool, default false) and change the permission assembly where the write permission "Microsoft.Capacity/reservationOrders/write" is added so that it is included only when both enable_archera and enable_archera_purchase_actions are true; update any places referencing enable_archera to leave read/telemetry behavior unchanged and gate purchase-related actions/role bindings on enable_archera_purchase_actions in addition to enable_archera.
🤖 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.
Inline comments:
In `@terraform/environments/aws/archera.tf`:
- Around line 133-155: Split the high-risk purchase permissions (the statements
with Sid "ReservedInstancesPurchase" and "SavingsPlansPurchase") out of the
existing Archera IAM policy and move them into a new, separate IAM policy
resource; add a new boolean input variable enable_archera_purchase_actions and
conditionally create/attach that new purchase policy only when
enable_archera_purchase_actions is true, leaving the original enable_archera =
true behavior to continue granting only read/telemetry permissions; update any
IAM attachment/module invocation that currently uses the single policy to
reference both policies conditionally and preserve the TODO comments about
requiring Archera approval.
- Around line 32-47: Update the Archera role trust policy to require
sts:ExternalId by un-commenting and enforcing the Condition block (add the
StringEquals = { "sts:ExternalId" = var.archera_external_id } clause in the
assume_role_policy Statement for "ArcheraAssumeRole") so the trust policy always
validates ExternalId when Archera assumes the role; additionally add a new
Terraform variable archera_external_id (string) and in the variables.tf add
validation that it is non-empty and required whenever enable_archera is true
(use a validation rule or conditional check to fail plan/apply if enable_archera
&& var.archera_external_id == ""), referencing the existing enable_archera flag
and the archera_external_id variable in the module.
In `@terraform/environments/azure/variables.tf`:
- Around line 545-556: Add a Terraform variable validation for
archera_azure_sp_object_id that enforces a non-empty, well-formed value when
enable_archera is true: inside the variable "archera_azure_sp_object_id"
declaration add a validation block that checks (var.enable_archera == false) OR
(the value is not empty and matches a GUID/UUID pattern) and return a clear
error message if the check fails; reference var.enable_archera and
var.archera_azure_sp_object_id in the validation to ensure early, descriptive
failure instead of deferring to apply-time role assignment.
In `@terraform/environments/gcp/archera.tf`:
- Around line 55-60: The listed permission
recommender.commitmentUtilizationInsights.update grants write access and should
be removed from the read-only block; edit the array where
"recommender.commitmentUtilizationInsights.update" appears (near the read-only
Recommender / Committed Use Discounts section) and delete that entry so only
"recommender.commitmentUtilizationInsights.get" and
"recommender.commitmentUtilizationInsights.list" remain, preserving formatting
and comments around the block.
In `@terraform/environments/gcp/variables.tf`:
- Around line 493-506: Add a validation block to the variable
"archera_gcp_service_account" so Terraform will fail fast when enable_archera is
true and the service account is empty or malformed; specifically, add a
conditional check that if var.enable_archera == true then
var.archera_gcp_service_account must be non-empty and match an
email/service-account pattern (e.g., user@project.iam.gserviceaccount.com) to
prevent creating a member value of "serviceAccount:". Update the variable
"archera_gcp_service_account" definition to include the validation rule and an
appropriate error_message referencing the variable and the enable_archera flag
so callers know to provide a valid service account email before applying.
---
Nitpick comments:
In `@terraform/environments/azure/archera.tf`:
- Around line 55-59: Current setup ties telemetry and purchase permissions to a
single flag (enable_archera); add a new variable enable_archera_purchase_actions
(bool, default false) and change the permission assembly where the write
permission "Microsoft.Capacity/reservationOrders/write" is added so that it is
included only when both enable_archera and enable_archera_purchase_actions are
true; update any places referencing enable_archera to leave read/telemetry
behavior unchanged and gate purchase-related actions/role bindings on
enable_archera_purchase_actions in addition to enable_archera.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: eccb27a1-a829-47ef-8961-73ecc27f9382
📒 Files selected for processing (12)
terraform/environments/aws/README.mdterraform/environments/aws/archera.tfterraform/environments/aws/dev.tfvars.exampleterraform/environments/aws/variables.tfterraform/environments/azure/README.mdterraform/environments/azure/archera.tfterraform/environments/azure/dev.tfvars.exampleterraform/environments/azure/variables.tfterraform/environments/gcp/README.mdterraform/environments/gcp/archera.tfterraform/environments/gcp/dev.tfvars.exampleterraform/environments/gcp/variables.tf
…lit, validation AWS: - enforce ExternalId in assume-role trust policy (confused-deputy protection) - split archera_purchase into a separate IAM policy gated by enable_archera_purchase_actions (default false) so read-only rollouts never accidentally include financial writes - add archera_external_id variable (sensitive, required when enable_archera=true) - add enable_archera_purchase_actions variable (bool, default false) Azure: - add UUID validation on archera_azure_sp_object_id when enable_archera=true - add enable_archera_purchase_actions variable; gate reservationOrders/write behind it via concat() so the initial rollout is read-only GCP: - remove recommender.commitmentUtilizationInsights.update (write action incorrectly placed in read-only block) - add email format validation on archera_gcp_service_account when enable_archera=true - add enable_archera_purchase_actions variable; gate recommender.commitments.create behind it via concat() All environments: dev.tfvars.example updated to include enable_archera_purchase_actions = false terraform fmt + validate pass for all three clouds.
CodeRabbit review — round 1 fixes (commit f3ba36a)All 5 Actionable items addressed, plus the Nitpick: AddressedAWS
Azure
GCP
All clouds:
@coderabbitai review |
|
Tip For best results, initiate chat on the files or code changes.
Triggering a fresh review of commit [review] |
|
@coderabbitai full review The 10 min since the previous re-review trigger have passed without a posted review. Please review commit f3ba36a which addresses the 5 actionable items + 1 nitpick from your round-1 review (ExternalId enforcement, AWS read/purchase policy split, Azure UUID validation, GCP removed update perm, GCP email validation, all clouds gained enable_archera_purchase_actions flag). |
|
Tip For best results, initiate chat on the files or code changes.
[full_review] |
|
@coderabbitai resolve The previous |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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.
Inline comments:
In `@terraform/environments/aws/README.md`:
- Around line 48-76: Update the README enablement example and resource table to
match the current Terraform split: add the required archera_external_id variable
and mention the optional enable_archera_purchase_actions flag; replace
references to the removed aws_iam_policy.archera_integration and
aws_iam_role_policy_attachment.archera_integration with
aws_iam_policy.archera_read and aws_iam_role_policy_attachment.archera_read, and
add entries for aws_iam_policy.archera_purchase and
aws_iam_role_policy_attachment.archera_purchase (note purchase policy is
conditional on enable_archera_purchase_actions), and ensure the example shows
enabling enable_archera = true alongside archera_aws_account_id and
archera_external_id.
In `@terraform/environments/aws/variables.tf`:
- Around line 503-515: Add a validation block to the variable
"archera_aws_account_id" so that when set it must be a 12-digit AWS account ID;
specifically ensure the value is either empty or matches the regex for twelve
digits (e.g., ^\d{12}$) and provide a clear message referencing enable_archera;
also update aws/archera.tf to guard generation of the trust principal ARN with
var.enable_archera to avoid building an ARN from an empty/malformed ID.
In `@terraform/environments/azure/README.md`:
- Around line 43-70: Update the README's "Enabling Archera" section to
accurately document the purchase-action flag: clarify that reservation purchase
write permission ("Microsoft.Capacity/reservationOrders/write") is only added
when enable_archera_purchase_actions = true, show the optional tfvars entry for
enable_archera_purchase_actions, and adjust the table entry for
azurerm_role_definition.archera_integration[0] to state it provides read-only
cost access by default and only adds RI purchase writes when
enable_archera_purchase_actions is enabled; reference the enable_archera and
archera_azure_sp_object_id example and the
azurerm_role_definition.archera_integration[0] and
azurerm_role_assignment.archera_integration[0] resources so operators review the
correct permission set before flipping flags.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 13a8b046-446b-4011-a64a-06ddc17c2758
📒 Files selected for processing (12)
terraform/environments/aws/README.mdterraform/environments/aws/archera.tfterraform/environments/aws/dev.tfvars.exampleterraform/environments/aws/variables.tfterraform/environments/azure/README.mdterraform/environments/azure/archera.tfterraform/environments/azure/dev.tfvars.exampleterraform/environments/azure/variables.tfterraform/environments/gcp/README.mdterraform/environments/gcp/archera.tfterraform/environments/gcp/dev.tfvars.exampleterraform/environments/gcp/variables.tf
…review Address 3 actionable findings from CodeRabbit's review of f3ba36a: 1. AWS README — sync with read/purchase split: add `archera_external_id` to enablement example, mention optional `enable_archera_purchase_actions` flag, replace stale `archera_integration` policy/attachment table entries with `archera_read` + `archera_purchase`. 2. AWS variables.tf — add validation block to `archera_aws_account_id` that fails fast if the value isn't a 12-digit account ID when `enable_archera = true` (avoids building an invalid trust principal ARN at apply time). 3. Azure README — clarify that reservation purchase write permission is gated on `enable_archera_purchase_actions = true`, not `enable_archera` alone; adjust the role-definition row to match. `terraform validate` passes for AWS and Azure with the new validation block.
|
@coderabbitai review CR-pass-2 fixes pushed in f8daec6:
|
|
Tip For best results, initiate chat on the files or code changes.
[review] |
|
@coderabbitai full review The previous |
|
Tip For best results, initiate chat on the files or code changes.
[full_review] |
CR loop complete — all 3 actionable items addressed
CI: all 4 checks green (sanity AWS, sanity Azure, frontend build, pre-commit). Per-thread fix confirmations posted above (replies to each CR comment with the specific resolution). |
Architectural pivot — shared module + thin callerAfter discussion with @cristim and a second agent, the consensus is to NOT keep this PR's Archera implementation as inline New shapeBoth Terraform call sites become thin module-wrapper files: # terraform/environments/aws/archera.tf (this PR — was inline)
module "archera" {
source = "../../iac/modules/archera/aws"
enable_archera = var.enable_archera
archera_aws_account_id = var.archera_aws_account_id
archera_external_id = var.archera_external_id
enable_archera_purchase_actions = var.enable_archera_purchase_actions
}
# iac/federation/aws-target/terraform/archera.tf (#314 — same module, same shape)
module "archera" { source = "../../../modules/archera/aws"; ... }Non-Terraform formats (CFN/Bicep/ARM, used by federation bundles) load the action list from What this means for this PRThis PR will be reshaped to land:
CFN/Bicep/ARM rendering, federation bundle plumbing, frontend checkbox, and the parity check are scoped to #314 — not this PR. CI gate
CoordinationA consensus sync has been posted to the multi-agent bus at |
Correction to my earlier commentRe-verified the bundle-flag worktree state with a parallel agent (
Coordination record: see |
…cation pages (closes #314) Introduces the Archera Insurance CTA at the two high-intent moments where a user is about to commit money, plus two education pages that explain what Archera Insurance is and how the integration works. **New module — frontend/src/archera.ts** - `renderArcheraCTA()`: returns a small, muted <p> with an inline <button> that reads "Worried about committing? Archera Insurance underwrites commitment-overuse — learn how it works →". Placed below the approval note in the Purchase modal, and before the Save/Cancel row in Plan-creation modals. - `openArcheraPage('what-is-archera' | 'how-it-works')`: renders a full-viewport overlay panel using DOM methods only (no innerHTML). Doesn't touch SPA routing state or the URL. - `closeArcheraPage()`: hides + clears the overlay. - `ARCHERA_SIGNUP_URL = 'https://archera.ai/signup?mode=cudly'` for attribution-tagged referral links. **Page A — "What is Archera Insurance?"** Plain-language explainer: commitment-overuse insurance, how Archera earns (sharing-of-savings), when it makes sense, what CUDly's role is. Cross-links to Page B. Signup link at bottom (target=_blank, rel="noopener noreferrer"). **Page B — "How the CUDly ↔ Archera integration works"** Step-by-step: sign up → Archera generates pre-filled IaC for AWS/GCP (or OAuth consent for Azure) → Archera ingests cost data → purchase commitments normally through CUDly. Disclaimers: Archera is third-party, no credentials stored in CUDly. Cross-links to Page A. Signup link at bottom. TODO(@cristim) markers flag all copy that needs final review. **Modal integration** - `recommendations.ts / openPurchaseModal`: appends `renderArcheraCTA()` inside `#purchase-details`, below the approval note. - `plans.ts / openCreatePlanModal + openNewPlanModal`: calls `injectPlanModalCTA()` (guarded against duplication with an id check) to insert the CTA before `.modal-buttons` in `#plan-form`. **CSS (styles/modals.css)**: `.archera-cta`, `.archera-cta-link`, `#archera-page-container`, `.archera-page-inner`, `.archera-page-back`, `.archera-signup-block`, `.archera-signup-btn`, `.archera-signup-note`. **HTML (index.html)**: adds `<div id="archera-page-container" role="region" aria-label="Archera Insurance information">` (hidden by default) before the modal stack. **Tests (archera.test.ts)**: 26 assertions covering renderArcheraCTA structure, page A/B content + crosslinks + signup link attributes, closeArcheraPage, and CTA injection in both Purchase and Plan modals. Nothing in backend/, cmd/, internal/, iac/, terraform/, or scripts/ is touched. This is a frontend-only change. Supersedes PR #310 and PR #315 (closed without merging; earlier iterations bundled IAM/IaC which was rejected by Archera-side review — see issue #314 for history).
…es + email mentions (closes #314) (#336) * feat(frontend): Archera Insurance CTA in purchase + plan modals + education pages (closes #314) Introduces the Archera Insurance CTA at the two high-intent moments where a user is about to commit money, plus two education pages that explain what Archera Insurance is and how the integration works. **New module — frontend/src/archera.ts** - `renderArcheraCTA()`: returns a small, muted <p> with an inline <button> that reads "Worried about committing? Archera Insurance underwrites commitment-overuse — learn how it works →". Placed below the approval note in the Purchase modal, and before the Save/Cancel row in Plan-creation modals. - `openArcheraPage('what-is-archera' | 'how-it-works')`: renders a full-viewport overlay panel using DOM methods only (no innerHTML). Doesn't touch SPA routing state or the URL. - `closeArcheraPage()`: hides + clears the overlay. - `ARCHERA_SIGNUP_URL = 'https://archera.ai/signup?mode=cudly'` for attribution-tagged referral links. **Page A — "What is Archera Insurance?"** Plain-language explainer: commitment-overuse insurance, how Archera earns (sharing-of-savings), when it makes sense, what CUDly's role is. Cross-links to Page B. Signup link at bottom (target=_blank, rel="noopener noreferrer"). **Page B — "How the CUDly ↔ Archera integration works"** Step-by-step: sign up → Archera generates pre-filled IaC for AWS/GCP (or OAuth consent for Azure) → Archera ingests cost data → purchase commitments normally through CUDly. Disclaimers: Archera is third-party, no credentials stored in CUDly. Cross-links to Page A. Signup link at bottom. TODO(@cristim) markers flag all copy that needs final review. **Modal integration** - `recommendations.ts / openPurchaseModal`: appends `renderArcheraCTA()` inside `#purchase-details`, below the approval note. - `plans.ts / openCreatePlanModal + openNewPlanModal`: calls `injectPlanModalCTA()` (guarded against duplication with an id check) to insert the CTA before `.modal-buttons` in `#plan-form`. **CSS (styles/modals.css)**: `.archera-cta`, `.archera-cta-link`, `#archera-page-container`, `.archera-page-inner`, `.archera-page-back`, `.archera-signup-block`, `.archera-signup-btn`, `.archera-signup-note`. **HTML (index.html)**: adds `<div id="archera-page-container" role="region" aria-label="Archera Insurance information">` (hidden by default) before the modal stack. **Tests (archera.test.ts)**: 26 assertions covering renderArcheraCTA structure, page A/B content + crosslinks + signup link attributes, closeArcheraPage, and CTA injection in both Purchase and Plan modals. Nothing in backend/, cmd/, internal/, iac/, terraform/, or scripts/ is touched. This is a frontend-only change. Supersedes PR #310 and PR #315 (closed without merging; earlier iterations bundled IAM/IaC which was rejected by Archera-side review — see issue #314 for history). * feat(frontend,email): address CR findings + scope additions (issue #314) Frontend (CR fixes): - archera.ts: save/restore focus around overlay open/close (CR: focus restoration on closeArcheraPage) - modals.css: raise #archera-page-container z-index from 900 to 1100 so overlay sits above .modal layers (CR: z-index below modals) - archera.test.ts: add global afterEach DOM teardown to prevent stale- node collisions between test suites (CR: missing teardown) Frontend (scope additions from coordinator): - archera.ts: update renderArcheraCTA copy to "Insure this commitment/ plan with Archera →"; add transparency disclosure section (Page A: "Why is CUDly telling me about this?", Page B: "Disclosure") carrying two non-negotiable facts: CUDly fully functional without Archera + Archera sponsors CUDly; add handleArcheraDeeplink() for deep-link routing from email; export ARCHERA_PAGE_A/B_PATH constants - app.ts: wire handleArcheraDeeplink() into init() after handlePurchaseDeeplink() - plans.ts: pass 'plan' context to renderArcheraCTA in injectPlanModalCTA - archera.test.ts: update CTA copy assertions; add disclosure tests (6); add handleArcheraDeeplink tests (3); total: 41 tests, all passing Backend (email templates — scope addition): - sender.go: add ArcheraEducationURL field to NotificationData; empty value silently omits the Archera block for backward compat - templates.go: add conditional Archera 7-day enrollment block to purchaseApprovalRequestTemplate (plain-text), purchaseApprovalRequest- HTMLTemplate (HTML), and purchaseConfirmationTemplate - handler_purchases.go, execution.go: populate ArcheraEducationURL as DashboardURL + "/archera-insurance" matching ARCHERA_PAGE_A_PATH - template_renderers_test.go: add 4 Go tests asserting Archera content in all three modified templates + absence test when URL is empty * refactor(api): extract archeraEducationURL helper to reduce sendPurchaseApprovalEmail cyclomatic complexity The if dashboardBase != "" guard added in the previous commit pushed sendPurchaseApprovalEmail from complexity 10 to 11, exceeding the gocyclo pre-commit threshold. Extracted the guard into a package-private archeraEducationURL helper; sendPurchaseApprovalEmail calls it inline without a branch, restoring complexity to 10. * refactor(archera): post-action offer modal + single education page Restructures the Archera Insurance flow into a post-action offer modal, collapses the previously split education pages into one, and tightens the copy. Frontend changes: - Replace the inline "Insure this {commitment,plan} with Archera →" CTA inside the Purchase and Plan-creation modals with a new post-action offer modal (openArcheraOfferModal). The modal pops after a successful Send-for-Approval submission (app.ts handleExecutePurchase + handleFanOutExecute) or plan creation (plans.ts savePlan). The user sees title + lead + brief disclosure, then a collapsed "Learn more" drop-down, then two equal-weight actions: "No thanks" and "Sign up at Archera →" (opens archera.ai in a new tab). - Merge the previously separate "What is Archera Insurance?" (Page A) and "How the integration works" (Page B) overlays into a single education page (buildArcheraPage). Both ARCHERA_PAGE_A_PATH and ARCHERA_PAGE_B_PATH still deep-link to the merged page (PAGE_B kept for backward compatibility with already-delivered email links). - "Learn more" is a native <details>/<summary> that expands the full education content inline within the offer modal. Summary text on the left, chevron on the right (rotates on open). Body inherits .archera- page-inner typography for visual parity with the standalone page. - Education content tightened: dedupe the lead-paragraph + "Why is CUDly telling me about this?" overlap, drop the four-bullet Disclaimers section in favour of a single closing "Full disclosure:" paragraph that absorbs the legal/scope points. Drop the "All Upfront" qualifier from "When it makes sense" and reframe the second use case from "finance team requires a safety net" to user-perspective "you want to be covered in case your usage drops". - "How it works" intro now explicitly states the 7-day enrollment window from each purchase. - Premium note clarifies the insurance fee is paid to Archera and the cloud commitment bought through CUDly is unaffected (same price, same billing) — replaces the earlier sharing-of-savings framing. - Add aria-haspopup="dialog" + aria-expanded toggling on the (now- removed) Columns popover trigger to expose dialog state to assistive tech. (No-op for the removed inline CTAs; this change is the modal's a11y surface.) - Drop the inline scripts' em-dashes from JSDoc + user-facing strings. Tests: - archera.test.ts rewritten: drops renderArcheraCTA + page A/B + plan- modal-CTA + purchase-modal-CTA describe blocks (those surfaces are gone). Adds openArcheraOfferModal describes covering visibility, context-dependent headlines, signup link attributes, No-thanks + backdrop + ESC close, Learn-more collapsible expand, re-open replace semantics. handleArcheraDeeplink test now verifies both legacy and current URL paths open the same merged page. 1605 frontend tests pass. * feat(email): inline expanded Archera section in approval + confirmation Replaces the 4-line "Learn more: <URL>" Archera block in the purchase- confirmation, purchase-approval-request (plain text), and approval- request (HTML) emails with the full education content inlined into the message body — so recipients don't need to click through to the dashboard to read what the option is, when it makes sense, and how it works. Structure mirrors the in-app offer modal's expanded "Learn more" content: - Header + 7-day enrollment window note - One-paragraph lead (covers the gap + non-gating) - "When it makes sense" (2 use cases) - "How it works" with the 3-step onboarding flow - Premium clarification (insurance fee is separate from the cloud commitment; same price, same billing) - Full-disclosure paragraph (sponsorship + scope + Archera-owns-terms) - Sign up CTA + permalink Always-expanded (no <details>/<summary>): Outlook desktop, Outlook.com, and mobile Outlook strip those, so the safest is a flat inline body. Apple Mail, iOS Mail, and Gmail web render the styled HTML naturally; all other clients fall back to the plain-text version. The original {{.ArcheraEducationURL}} is kept as a "Permalink:" at the bottom of each block — preserves the existing tests' URL assertions and gives a fallback for forwarded emails, bookmarks, or clients that mangle the inlined HTML. 310 Go tests still pass. * fix(frontend/archera): cleanup leaked listener + add focus trap to dialog Address two CR findings on PR #336: 1. **Stale keydown listener leak**: openArcheraOfferModal added a document-level keydown handler (ESC closes) and stored its cleanup in `_offerModalCleanup` on every call, but didn't first invoke the prior cleanup. A re-open without an explicit close in between leaked the previous handler. Fix: call `_offerModalCleanup()` (if set) at the top of openArcheraOfferModal before attaching the new handler. Idempotent — no-op when no prior open is in flight. 2. **No focus trap on the dialog panel**: the panel declares `role="dialog" aria-modal="true"` but Tab / Shift+Tab let keyboard users escape into the background app. That's an a11y regression for an "aria-modal=true" element. Fix: attach a panel-level keydown handler that intercepts Tab — Tab on last focusable wraps to first, Shift+Tab on first wraps to last. Focusables are re-queried on each Tab press (not cached at modal-build time) so the Tab traversal picks up the additional focusables that the <details> drop-down expands when opened. Trap handler is torn down alongside the ESC handler by the merged `_offerModalCleanup` closure. Tests in archera.test.ts: - `re-opening tears down the previous open's ESC listener (no leak)` spies on document.addEventListener / removeEventListener and asserts the second open both adds AND removes one keydown handler. - `traps Tab focus inside the panel (Tab from last → first)` focuses the last focusable, dispatches Tab, asserts focus wraps to the first and the event was preventDefaulted. - `traps Shift+Tab focus inside the panel (Shift+Tab from first → last)` the mirror case. 1608 frontend tests pass (3 new).

Summary
Adds
enable_archera = falsescaffolding to all three cloud environments (AWS, Azure, GCP) so non-Archera customers see no drift. When a customer setsenable_archera = true, the IaC creates the minimal identity grants needed by Archera's integration.What's in each cloud
AWS (
terraform/environments/aws/archera.tf)enable_archera(bool, defaultfalse),archera_aws_account_id(string, default"")aws_iam_role(cudly-archera-integration) trusted byarn:aws:iam::<archera_aws_account_id>:root, with anaws_iam_policycovering:ce:Get*,ce:List*), CUR (cur:DescribeReportDefinitions), Reserved Instances (ec2:Describe*), Savings Plans (savingsplans:Describe*)ec2:PurchaseReservedInstancesOffering,ec2:ModifyReservedInstances,savingsplans:CreateSavingsPlanAzure (
terraform/environments/azure/archera.tf)enable_archera,archera_azure_sp_object_idazurerm_role_definition(custom, subscription-scoped) withMicrosoft.CostManagement/*/read,Microsoft.Consumption/*/read,Microsoft.Billing/*/read,Microsoft.Capacity/reservations/read,Microsoft.Capacity/reservationOrders/read|writeazurerm_role_assignmentto Archera's service principal (principal_type = "ServicePrincipal")GCP (
terraform/environments/gcp/archera.tf)enable_archera,archera_gcp_service_accountgoogle_project_iam_custom_role(stage=BETA, project-scoped) with billing read, recommender CUD read + creategoogle_project_iam_memberbinding to Archera's service accountIAM split placement
Per the repo's bootstrap-vs-runtime split (CLAUDE.md §"CI/CD IAM"): Archera is a runtime integration — it reads cost telemetry and executes purchases during normal operation, not during Terraform deploys. All three
archera.tffiles therefore live in the main environment (alongsidecompute.tf,database.tf) rather than inci-cd-permissions/.Verification
terraform fmt -checkclean on all 3 environmentsterraform validatepasses on all 3 environments withenable_archera = false(default, count=0).tfvarsfiles modified — only.examplefiles updatedOut of scope (follow-up PRs)
Per the issue body's suggestion of three per-cloud sub-PRs: this single scaffolding PR lands the structural gating and provisional lists for all three clouds at once (lower review risk since nothing is enabled by default). Separate follow-up PRs per cloud can narrow the scope list once Archera's docs are consulted.
Test plan
@cristimconfirms the scope list against Archera's integration docs (or narrows it)enable_archera = truein the target environment's tfvars and runsterraform plan— no new resources should appear for other environmentsenable_archera = truecreates 3 resources: role, policy, attachmentSummary by CodeRabbit
New Features
Documentation