Skip to content

RE1-T115 More paddle fixes#342

Merged
ucswift merged 1 commit intomasterfrom
develop
Apr 24, 2026
Merged

RE1-T115 More paddle fixes#342
ucswift merged 1 commit intomasterfrom
develop

Conversation

@ucswift
Copy link
Copy Markdown
Member

@ucswift ucswift commented Apr 24, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Improved Paddle checkout initialization validation with clearer error messaging when payment configuration is incomplete or invalid.
  • Tests

    • Added configuration validation test coverage for payment provider settings.
  • Chores

    • Updated deployment infrastructure configuration and strengthened security settings.

@gitguardian
Copy link
Copy Markdown

gitguardian Bot commented Apr 24, 2026

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
31747311 Triggered Generic High Entropy Secret fffa946 Tests/Resgrid.Tests/Config/PaymentProviderConfigTests.cs View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@request-info
Copy link
Copy Markdown

request-info Bot commented Apr 24, 2026

Thanks for opening this, but we'd appreciate a little more information. Could you update it with more details?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 24, 2026

📝 Walkthrough

Walkthrough

Introduces Paddle configuration validation methods with normalization logic to ensure environment and client-token values are properly formatted. Updates the subscription controller to validate Paddle configuration and gate checkout initialization. Extends view models with Paddle readiness flags. Modifies subscription views to conditionally initialize Paddle based on validated configuration. Updates Kubernetes deployment manifest with enhanced security and storage configurations.

Changes

Cohort / File(s) Summary
Paddle Configuration Validation
Core/Resgrid.Config/PaymentProviderConfig.cs, Tests/Resgrid.Tests/Config/PaymentProviderConfigTests.cs
Added IsValidPaddleEnvironment() and IsValidPaddleClientToken() validators with regex pattern matching; updated GetPaddleEnvironment() and GetPaddleClientToken() to normalize inputs via trim and lowercase; comprehensive test coverage for normalization and validation edge cases.
Subscription Controller
Web/Resgrid.Web/Areas/User/Controllers/SubscriptionController.cs
Modified SelectRegistrationPlan and Index actions to validate Paddle configuration and set CanInitializePaddleCheckout and PaddleConfigurationError flags on view models before rendering.
Subscription View Models
Web/Resgrid.Web/Areas/User/Models/Subscription/SelectRegistrationPlanView.cs, Web/Resgrid.Web/Areas/User/Models/Subscription/SubscriptionView.cs
Added CanInitializePaddleCheckout (bool) and PaddleConfigurationError (string) properties to both models.
Subscription Views
Web/Resgrid.Web/Areas/User/Views/Subscription/Index.cshtml, Web/Resgrid.Web/Areas/User/Views/Subscription/SelectRegistrationPlan.cshtml
Serialized Paddle configuration values to JSON for client-side consumption; gated Paddle SDK initialization on CanInitializePaddleCheckout flag; added client-side validation with user feedback when Paddle checkout is unavailable.
Kubernetes Deployment
Web/Resgrid.Web.Tts/k8s/deployment.yaml
Migrated to namespaced environment variables (RESGRID__*); added security hardening (seccomp profile, capability drops, startup/readiness/liveness probes); switched ephemeral storage from emptyDir to Longhorn-backed PVC; added Ingress resource for tts.example.com; expanded TTS configuration parameters.

Sequence Diagram

sequenceDiagram
    participant User
    participant View as Subscription View
    participant Controller as SubscriptionController
    participant Config as PaymentProviderConfig
    participant Client as Browser/JS
    
    User->>View: Request subscription page
    View->>Controller: GET request
    Controller->>Config: GetPaddleEnvironment()
    Config-->>Controller: Normalized env value
    Controller->>Config: GetPaddleClientToken()
    Config-->>Controller: Normalized token
    Controller->>Config: IsValidPaddleEnvironment(env)
    Config-->>Controller: Validation result
    Controller->>Config: IsValidPaddleClientToken(token)
    Config-->>Controller: Validation result
    Controller->>Controller: Set CanInitializePaddleCheckout flag
    Controller-->>View: Render with validation flags
    View->>Client: Serialize config as JSON
    Client->>Client: Check CanInitializePaddleCheckout?
    alt Valid Configuration
        Client->>Client: Initialize Paddle SDK
    else Invalid Configuration
        Client->>User: Show "Checkout Unavailable" alert
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • RE1-T112 Fixes #324: Modifies subscription views' Paddle checkout initialization and client-side checkout logic, overlapping with view changes in this PR.
  • RE1-T115 Fixing Paddle new sub issue #341: Updates SubscriptionController to change Paddle checkout initialization decision-making, directly related to controller validation additions in this PR.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'RE1-T115 More paddle fixes' is vague and lacks specificity about the actual changes; it uses a ticket reference and non-descriptive language ('More paddle fixes') that doesn't convey meaningful details about the changeset. Replace with a more specific title that describes the main change, such as 'Add Paddle configuration validation and normalization' or 'Validate Paddle environment and token configuration'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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 develop

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.

Copy link
Copy Markdown
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Web/Resgrid.Web/Areas/User/Views/Subscription/Index.cshtml (1)

297-308: ⚠️ Potential issue | 🟡 Minor

Consider surfacing the Paddle configuration error inline on this page, consistent with SelectRegistrationPlan.cshtml.

SelectRegistrationPlan.cshtml (lines 135-140) renders a visible alert alert-danger when Model.IsPaddleDepartment && !Model.CanInitializePaddleCheckout && PaddleConfigurationError is populated, but Index.cshtml only reveals the error via a Swal dialog after the user clicks Buy Yearly/Buy Monthly. For a department admin who is actively troubleshooting a misconfiguration, an inline banner (placed alongside the existing SubscriptionErrorMessage block) provides faster, self-service diagnosis and keeps the two subscription surfaces consistent.

💡 Suggested placement
                     `@if` (ViewBag.SubscriptionErrorMessage != null)
                     {
                         <div class="row">
                             <div class="col-xs-12">
                                 <div class="alert alert-danger alert-block">
                                     <h4 class="alert alert-heading">@localizer["Warning"]</h4>
                                     `@ViewBag.SubscriptionErrorMessage`
                                 </div>
                             </div>
                         </div>
                     }
+                    `@if` (Model.IsPaddleDepartment && !Model.CanInitializePaddleCheckout && !string.IsNullOrWhiteSpace(Model.PaddleConfigurationError))
+                    {
+                        <div class="row">
+                            <div class="col-xs-12">
+                                <div class="alert alert-danger alert-block">
+                                    <strong>Paddle Checkout Unavailable:</strong> `@Model.PaddleConfigurationError`
+                                </div>
+                            </div>
+                        </div>
+                    }
                     <hr>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Web/Resgrid.Web/Areas/User/Views/Subscription/Index.cshtml` around lines 297
- 308, Add an inline alert that surfaces the Paddle configuration error on the
subscription Index page similar to SelectRegistrationPlan.cshtml: inside
Index.cshtml, next to the existing ViewBag.SubscriptionErrorMessage block, add a
conditional block that checks Model.IsPaddleDepartment &&
!Model.CanInitializePaddleCheckout &&
!String.IsNullOrEmpty(Model.PaddleConfigurationError) and renders a <div
class="alert alert-danger"> showing Model.PaddleConfigurationError (optionally
with `@localizer`["Warning"] heading) so admins see the misconfiguration banner
without invoking the Swal dialog when clicking Buy Yearly/Buy Monthly.
🧹 Nitpick comments (2)
Tests/Resgrid.Tests/Config/PaymentProviderConfigTests.cs (1)

41-43: Use a test_-prefixed token in this fixture to avoid secret-scanner false positives.

The value is Paddle's public documentation example and not a real credential, but using a live_ prefix in test data trips Betterleaks (high severity in CI) and similar scanners. Since the regex treats test_ and live_ equivalently, switching to a test_ token keeps coverage identical while silencing the finding and making the intent "this is a test fixture" clearer.

♻️ Proposed change
-				PaymentProviderConfig.PaddleProductionClientToken = "  live_7d279f61a3499fed520f7cd8c08  ";
+				PaymentProviderConfig.PaddleProductionClientToken = "  test_7d279f61a3499fed520f7cd8c08  ";

-				PaymentProviderConfig.GetPaddleClientToken().Should().Be("live_7d279f61a3499fed520f7cd8c08");
+				PaymentProviderConfig.GetPaddleClientToken().Should().Be("test_7d279f61a3499fed520f7cd8c08");

The same applies to line 52 ([TestCase("live_7d279f61a3499fed520f7cd8c08", true)]) if you want to fully silence the scanner across the file.

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

In `@Tests/Resgrid.Tests/Config/PaymentProviderConfigTests.cs` around lines 41 -
43, Replace the test data Paddle token strings that use a "live_" prefix with a
clearly non-secret "test_" prefixed token to avoid secret-scanner false
positives; specifically update the PaddleProductionClientToken assignment
(PaymentProviderConfig.PaddleProductionClientToken) and any related test case
entries that pass "live_7d279f61a3499fed520f7cd8c08" (e.g., the TestCase that
calls GetPaddleClientToken) to use "test_7d279f61a3499fed520f7cd8c08" so
assertions against PaymentProviderConfig.GetPaddleClientToken() remain identical
but scanners are silenced.
Web/Resgrid.Web/Areas/User/Controllers/SubscriptionController.cs (1)

81-99: LGTM — clean extraction into a pure static helper.

Centralizing the Paddle configuration/validation into a pure tuple-returning helper is a nice fit with the codebase's functional leanings, and the early-return for non-Paddle departments keeps the happy path flat. Reuse between SelectRegistrationPlan and Index eliminates duplication.

Minor nit: the isPaddleDepartment && !canInitializePaddleCheckout check on line 96 is redundant — isPaddleDepartment is already guaranteed true at that point due to the early return on line 83-84. You can simplify to !canInitializePaddleCheckout ? GetPaddleConfigurationError(...) : null. Not a functional issue.

As per coding guidelines: "Prefer pure methods over methods with side effects".

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

In `@Web/Resgrid.Web/Areas/User/Controllers/SubscriptionController.cs` around
lines 81 - 99, GetPaddleCheckoutConfiguration contains a redundant check: the
ternary uses "isPaddleDepartment && !canInitializePaddleCheckout" but
isPaddleDepartment is already true due to the early return; simplify the ternary
to check only "!canInitializePaddleCheckout" and return
GetPaddleConfigurationError(paddleEnvironment, paddleClientToken) when that is
true, otherwise null, keeping the rest of the tuple and method logic unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Web/Resgrid.Web.Tts/k8s/deployment.yaml`:
- Around line 174-197: The Ingress resource (metadata name resgrid-tts) must
declare an ingress class and enable TLS: add spec.ingressClassName: nginx to
ensure an nginx controller will reconcile it (don't rely solely on nginx.*
annotations), and add a spec.tls block with hosts: ["tts.example.com"] and a
secretName (e.g., resgrid-tts-tls) that will hold the certificate (use your
cert-manager-issued secret name if you use cert-manager). Ensure the host under
spec.rules still matches tts.example.com and that the secretName is
created/managed by your certificate issuer.

---

Outside diff comments:
In `@Web/Resgrid.Web/Areas/User/Views/Subscription/Index.cshtml`:
- Around line 297-308: Add an inline alert that surfaces the Paddle
configuration error on the subscription Index page similar to
SelectRegistrationPlan.cshtml: inside Index.cshtml, next to the existing
ViewBag.SubscriptionErrorMessage block, add a conditional block that checks
Model.IsPaddleDepartment && !Model.CanInitializePaddleCheckout &&
!String.IsNullOrEmpty(Model.PaddleConfigurationError) and renders a <div
class="alert alert-danger"> showing Model.PaddleConfigurationError (optionally
with `@localizer`["Warning"] heading) so admins see the misconfiguration banner
without invoking the Swal dialog when clicking Buy Yearly/Buy Monthly.

---

Nitpick comments:
In `@Tests/Resgrid.Tests/Config/PaymentProviderConfigTests.cs`:
- Around line 41-43: Replace the test data Paddle token strings that use a
"live_" prefix with a clearly non-secret "test_" prefixed token to avoid
secret-scanner false positives; specifically update the
PaddleProductionClientToken assignment
(PaymentProviderConfig.PaddleProductionClientToken) and any related test case
entries that pass "live_7d279f61a3499fed520f7cd8c08" (e.g., the TestCase that
calls GetPaddleClientToken) to use "test_7d279f61a3499fed520f7cd8c08" so
assertions against PaymentProviderConfig.GetPaddleClientToken() remain identical
but scanners are silenced.

In `@Web/Resgrid.Web/Areas/User/Controllers/SubscriptionController.cs`:
- Around line 81-99: GetPaddleCheckoutConfiguration contains a redundant check:
the ternary uses "isPaddleDepartment && !canInitializePaddleCheckout" but
isPaddleDepartment is already true due to the early return; simplify the ternary
to check only "!canInitializePaddleCheckout" and return
GetPaddleConfigurationError(paddleEnvironment, paddleClientToken) when that is
true, otherwise null, keeping the rest of the tuple and method logic unchanged.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ccb917b4-a6be-414c-abcd-d58d3a8b538c

📥 Commits

Reviewing files that changed from the base of the PR and between 44f8514 and fffa946.

📒 Files selected for processing (8)
  • Core/Resgrid.Config/PaymentProviderConfig.cs
  • Tests/Resgrid.Tests/Config/PaymentProviderConfigTests.cs
  • Web/Resgrid.Web.Tts/k8s/deployment.yaml
  • Web/Resgrid.Web/Areas/User/Controllers/SubscriptionController.cs
  • Web/Resgrid.Web/Areas/User/Models/Subscription/SelectRegistrationPlanView.cs
  • Web/Resgrid.Web/Areas/User/Models/Subscription/SubscriptionView.cs
  • Web/Resgrid.Web/Areas/User/Views/Subscription/Index.cshtml
  • Web/Resgrid.Web/Areas/User/Views/Subscription/SelectRegistrationPlan.cshtml

Comment on lines +174 to +197
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: resgrid-tts
labels:
app.kubernetes.io/name: resgrid-tts
app.kubernetes.io/part-of: resgrid
app.kubernetes.io/managed-by: fleet
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
spec:
rules:
- host: tts.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: resgrid-tts
port:
number: 80
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.

⚠️ Potential issue | 🟠 Major

Ingress is missing ingressClassName and TLS.

Two gaps worth addressing before this rolls out:

  1. No ingressClassName. The nginx-specific annotations alone are not sufficient on clusters without a default IngressClass; the resource will be created but never reconciled by any controller. Prefer the modern spec.ingressClassName: nginx field over the deprecated kubernetes.io/ingress.class annotation.
  2. No TLS. The service exposes StaticPromptAdminKey-guarded admin endpoints and playback URLs. Serving over plain HTTP leaks the admin key and any request payloads. Add a tls: block (e.g., cert-manager-issued) for tts.example.com.
🛡️ Suggested change
 spec:
+  ingressClassName: nginx
+  tls:
+    - hosts:
+        - tts.example.com
+      secretName: resgrid-tts-tls
   rules:
     - host: tts.example.com
       http:
         paths:
           - path: /
             pathType: Prefix
             backend:
               service:
                 name: resgrid-tts
                 port:
                   number: 80
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Web/Resgrid.Web.Tts/k8s/deployment.yaml` around lines 174 - 197, The Ingress
resource (metadata name resgrid-tts) must declare an ingress class and enable
TLS: add spec.ingressClassName: nginx to ensure an nginx controller will
reconcile it (don't rely solely on nginx.* annotations), and add a spec.tls
block with hosts: ["tts.example.com"] and a secretName (e.g., resgrid-tts-tls)
that will hold the certificate (use your cert-manager-issued secret name if you
use cert-manager). Ensure the host under spec.rules still matches
tts.example.com and that the secretName is created/managed by your certificate
issuer.

@ucswift
Copy link
Copy Markdown
Member Author

ucswift commented Apr 24, 2026

Approve

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

This PR is approved.

@ucswift
Copy link
Copy Markdown
Member Author

ucswift commented Apr 24, 2026

Approve

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

This PR is approved.

@ucswift
Copy link
Copy Markdown
Member Author

ucswift commented Apr 24, 2026

Approve

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

This PR is approved.

@ucswift ucswift merged commit 35af15d into master Apr 24, 2026
17 of 19 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Apr 25, 2026
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