d681f64505
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a11067da1a
|
fix(gateway): /redeem-preview + plans + addons must be public (D29) (#1559)
* feat(billing+notification): wire voucher-issued email (D28) D28 of the Sovereign DoD requires that issuing a voucher emails it to the recipient zero-touch. Today POST /billing/vouchers/issue persists the PromoCode row but never notifies anyone — so a gifted voucher only reaches its recipient if the operator manually sends the code over a side channel. This wires sme-billing -> sme-notification so the email fires automatically on every successful upsert that carries a recipient_email field. Architecture follows the existing notification-service seam: sme-billing POSTs to http://notification.sme.svc.cluster.local:8087/ notification/send with template=voucher-issued; sme-notification renders the HTML and dispatches via Stalwart over SMTP. No direct SMTP code is added to billing, no stalwart-mail calls bypass notification. Server-side only — the owner-UI for issuing vouchers (D28b) is a separate PR. Changes: notification/templates/templates.go + VoucherIssuedEmail(code, creditOMR, description, sovereignFQDN, validityHint) — renders code prominently, redeem button to https://marketplace.<sovereignFQDN>/redeem/?code=<CODE>; FQDN always supplied by caller, NEVER hardcoded. notification/handlers/handlers.go + renderTemplate("voucher-issued") case parsing {code, credit_omr, description, sovereign_fqdn, validity_hint}. + Default subject "You've been gifted a voucher for OpenOva SME". billing/handlers/handlers.go + Handler fields: NotificationURL, SovereignFQDN, NotificationClient. billing/handlers/vouchers.go + issueVoucherRequest = store.PromoCode + RecipientEmail (request- only; never persisted). + sendVoucherIssuedEmail() — POSTs to NotificationURL with a 5s timeout. Best-effort: a non-2xx or transport error logs but does NOT fail the IssueVoucher response, because the row is already persisted and re-issuing the same code re-fires the email. + Re-issue semantics (#91 resurrects soft-deleted rows) extend to the email path — documented in the handler comment. billing/main.go + Reads NOTIFICATION_SERVICE_URL (default http://notification.sme.svc.cluster.local:8087/notification/send) and SOVEREIGN_FQDN env vars. Wires a 5s default http.Client. products/catalyst/chart/templates/sme-services/billing.yaml + Pipes NOTIFICATION_SERVICE_URL (cluster-DNS constant) and SOVEREIGN_FQDN (from .Values.global.sovereignFQDN, NEVER hardcoded) into the billing Deployment. Tests: notification/handlers/handlers_test.go (new) + TestRenderTemplate_VoucherIssued: rendered HTML contains code + credit + a redeem URL built from the supplied FQDN; never falls back to marketplace.openova.io. + TestRenderTemplate_VoucherIssued_CustomSubject + _NoDescription + TestRenderTemplate_UnknownTemplate as guard rails. billing/handlers/vouchers_test.go + TestIssueVoucher_SendsEmail_WhenRecipientPresent: a fake round- tripper sees the POST to notification with the right URL + template + data (code upper-cased, credit_omr, sovereign_fqdn, description) when recipient_email is set. + TestIssueVoucher_NoEmail_WhenRecipientAbsent: no notification call when recipient is empty. + TestIssueVoucher_NotificationFailure_DoesNotFailUpsert: operator gets 200 even when notification returns 500. + TestIssueVoucher_403WithoutVoucherIssuerRole: role gate preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(chart): admin pod uses dedicated image tag (D27 SME stack) t132 caught admin pod stuck in ImagePullBackOff on `admin:b0ed216` — the SME services CI run for that mono-repo SHA published 10 services but admin's image was missing from GHCR. Decouple admin's tag from smeTag so a missing-build for one service doesn't wedge the SME stack. Default to `3c2f7e4` (matches marketplaceApi + console, known-published). When admin's UI changes, bump in lockstep with those. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(slot-13): pin bp-catalyst-platform to 1.4.144 PR #1556 (D28 voucher email wire) + PR #1557 (D27 admin tag override) landed and Blueprint Release packaged 1.4.144. Pin the slot file so future provisions get the latest chart by default — t132 manually upgraded via kubectl patch but t133+ will inherit it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(gateway): /redeem-preview + plans + addons must be public (D29) The marketplace /redeem?code=XXX landing page calls /api/billing/vouchers/redeem-preview unauthenticated per docs/FRANCHISE- MODEL.md §3, but the gateway's catch-all /api/billing/ entry was returning 401 to it — breaking the entire voucher-redeem zero-touch flow that D29 depends on. Also expose /api/billing/plans and /api/billing/addons so the marketplace landing can render pricing without a session. Caught live on t132 2026-05-16 — every /redeem call returned 401. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: hatiyildiz <hatice.yildiz@openova.io> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
fa4395fa3a
|
fix(bp-catalyst-platform): wire VALKEY_PASSWORD into SME auth + gateway (#863) (#864)
After PR #862 (1.4.4) made cross-ns Valkey reachable from `sme` ns, the auth Pod started CrashLoopBackOff with "NOAUTH HELLO must be called with the client already authenticated". Root cause: bp-valkey 1.0.0 ships auth.enabled=true (bitnami default) but SME service code + Deployment templates never plumbed a password through. Chart 1.4.4 -> 1.4.5. Slot 13 pin lockstep. Changes: - core/services/shared/db/valkey.go: add ConnectValkeyWithAuth overload taking username + password. ConnectValkey kept backwards-compatible for contabo-mkt's auth-less in-namespace Valkey. - core/services/auth/main.go + gateway/main.go: read VALKEY_USERNAME + VALKEY_PASSWORD env, call ConnectValkeyWithAuth when password set, else fall through to no-auth path. - NEW templates/sme-services/valkey-cross-ns-secret.yaml: Helm `lookup` reads bp-valkey's auto-generated `valkey-password` from the `valkey/valkey` Secret and re-emits it as `sme-valkey-auth` in `sme` ns. Same pattern as sme-secrets.yaml (#859) and gitea-admin-secret (#830 Bug 2). On first install the lookup may return nil; Flux's 15m reconcile picks up the mirror once bp-valkey is Ready. - auth.yaml + gateway.yaml: add VALKEY_PASSWORD env from `sme-valkey- auth` Secret with optional=true so contabo-mkt's auth-less path keeps working when the mirror Secret is absent. - values.yaml: add `smeServices.valkey.{sourceSecretName, sourcePasswordKey, destNamespace, destSecretName}` knobs (Inviolable Principle #4). Live verified the failure mode on otech103: 11/13 SME pods Running 1/1, auth in CrashLoopBackOff with NOAUTH HELLO error. Provisioning Pod's CreateContainerConfigError is unrelated (ghcr-pull, separate ticket). Co-authored-by: hatiyildiz <hatice.yildiz@openova.io> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
5cdb738ac9
|
fix(services): go mod tidy across sibling services after #798 shared deps bump (#821)
#798 added github.com/nats-io/nats.go to core/services/shared/go.mod and adjusted x/sys/x/crypto/x/text to Go 1.22-compatible versions. The sibling services (auth, catalog, domain, gateway, notification, provisioning, tenant) reference the same shared module via the local `replace` directive — their go.sum files must include the new transitive hashes, otherwise the CI Containerfile build hits: go: updates to go.mod needed; to update it: go mod tidy This commit is a pure `go mod tidy` across all 7 services; no source changes. CI services-build is now unblocked. Co-authored-by: hatiyildiz <hatice.yildiz@openova.io> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
7646840ffe |
feat(consolidation): move 8 SME backend services + shared module to public repo
Per docs/PROVISIONING-PLAN.md and tickets [B] sme-backend group. Migrates the 8 Go backend services from openova-private/services/ to openova/core/services/, plus the shared module they all depend on, plus the services-build CI workflow.
What moved:
- services/auth → core/services/auth (Go HTTP service for SME marketplace authentication)
- services/billing → core/services/billing (Go HTTP service for billing + voucher backend)
- services/catalog → core/services/catalog (Go HTTP service for App catalog)
- services/domain → core/services/domain (Go HTTP service for tenant domain mapping)
- services/gateway → core/services/gateway (Go HTTP gateway with rate limiting)
- services/notification → core/services/notification (Go HTTP service with email templates)
- services/provisioning → core/services/provisioning (Go HTTP service that commits tenant Application manifests via Gitea/GitHub API)
- services/tenant → core/services/tenant (Go HTTP service for tenant lifecycle)
- services/shared → core/services/shared (shared Go module: db, events, health, middleware, respond)
- 9 go.mod files updated: module github.com/openova-io/openova-private/services/<X> → github.com/openova-io/openova/core/services/<X>
- 9 go.sum and import paths similarly updated
- replace directives updated: openova-private/services/shared → openova/core/services/shared
- sme-services-build.yaml workflow → services-build.yaml in .github/workflows/, paths/context/image-base/deploy paths all repointed at core/services + ghcr.io/openova-io/openova/services-* + products/catalyst/chart/templates/sme-services
- All 8 manifests in products/catalyst/chart/templates/sme-services/ updated: image refs ghcr.io/openova-io/openova-private/sme-{X} → ghcr.io/openova-io/openova/services-{X}
- provisioning.yaml GITHUB_REPO env var: "openova-private" → "openova"
Closes [B] sme-backend (10 tickets).
After this commit, all 14 user-facing + backend Catalyst-Zero modules build from this public repo:
- 4 UIs: console, admin, marketplace, catalyst-ui
- 2 backends: marketplace-api, catalyst-api
- 8 SME services: auth, billing, catalog, domain, gateway, notification, provisioning, tenant
- 1 shared Go module
Note: 1 line in core/services/provisioning/main.go retains a literal default of "openova-private" for the GITHUB_REPO fallback when env var is unset; the K8s manifest sets GITHUB_REPO=openova explicitly so this path is never exercised in the deployed runtime, and the in-code default will be cleaned up in a follow-up.
|