Skip to content

feat: add billing ActivityPolicies for BillingAccount + PaymentMethod#620

Draft
mattdjenkinson wants to merge 3 commits into
mainfrom
feat/billing-activity-policies
Draft

feat: add billing ActivityPolicies for BillingAccount + PaymentMethod#620
mattdjenkinson wants to merge 3 commits into
mainfrom
feat/billing-activity-policies

Conversation

@mattdjenkinson
Copy link
Copy Markdown
Contributor

Summary

Adds ActivityPolicy coverage for the user-facing billing API resources introduced in milo-os/billing v0.2.0 so organisation operators can see who created billing accounts, attached projects, and added or removed payment methods in the activity timeline.

Lives under `config/services/activity/policies/billing/` and wired in alongside the existing `iam`, `resourcemanager`, `identity-provider`, `notes`, `notification`, `quota` components.

Coverage

Resource Why
`BillingAccount` User-created; surfaces `contactInfo.businessName` / `contactInfo.name` in the summary when present, falling back to the resource name.
`BillingAccountBinding` Surfaces `projectRef` + `billingAccountRef` so the timeline reads ` bound project X to billing account Y` even when the binding's own `metadata.name` is generated.
`PaymentMethod` Tracks the user-driven add / remove path. Async attach phase is system-actor-owned, gets filtered out as noise.

Out of scope

  • `PaymentMethodClass` — cluster-scoped, operator-managed via Git; no user audit trail.
  • `MeterDefinition`, `MonitoredResourceType` — admin-managed.
  • `stripe.billing.miloapis.com/{StripeProviderConfig, StripePaymentMethod}` — controller-owned, written exclusively under the `system:` actor and consumed by billing's user-facing `PaymentMethod` rather than directly by humans.

Validation

`kustomize build config/services/activity` clean; new policies render alongside the existing ones.

Add an enhancement proposal for surfacing human-readable resource
labels and product-level grouping on the quota system.

Key changes proposed:
- New cluster-scoped Product CRD under quota.miloapis.com/v1alpha1
  carrying display name and description for a product (e.g. AI Edge)
- New optional displayName and productRef fields on
  ResourceRegistrationSpec so each registered resource can advertise
  its friendly label and product membership
- Propagation of display metadata into AllowanceBucket.status so the
  cloud portal renders the quota page from a single list call
- Staff-portal admin surface for curating Product objects and editing
  the new display fields, layered on top of the Kubernetes API

Tracking issue: datum-cloud/enhancements#735
Two pieces of feedback on datum-cloud/enhancements#735:

1. Drop the separate Product CRD. Service-layer modelling belongs in
   the upcoming Milo service catalog, not in quota.miloapis.com. Add
   taxonomy fields (product, productDisplayName, category) directly to
   ResourceRegistrationSpec instead. The service catalog will populate
   spec.taxonomy once it lands; for now operators author it directly.
2. Drop controller-driven propagation into AllowanceBucket.status.
   Join registration metadata to buckets at the GraphQL layer via a
   field resolver with a per-request DataLoader and short TTL cache.
   No AllowanceBucket CRD changes; ResourceRegistration stays the
   single source of truth.

Cloud-portal switches the quota page to a GraphQL query (already the
pattern used for organizations/users). Staff-portal edit surface
narrows to ResourceRegistration display-field editing — no Products
admin since there is no Product resource.
Surface user-facing billing API operations in the activity timeline so
organisation operators can see who created billing accounts, attached
projects, and added or removed payment methods. Follows the existing
service.activity convention (resourcemanager, iam, notification, ...):

- billing/billingaccount-policy.yaml — auditRules tiered on contactInfo.
  businessName, contactInfo.name, then the resource name so create
  entries prefer the human-recognisable label without breaking when
  the audit record lacks a requestObject (deletes).
- billing/billingaccountbinding-policy.yaml — summarises bindings using
  the projectRef + billingAccountRef names so the timeline is
  meaningful even when the binding's own metadata.name is generated.
- billing/paymentmethod-policy.yaml — surfaces the user-driven add /
  remove path on a PaymentMethod. The provider controller owns the
  asynchronous attach phase and writes via the system: user, which the
  shared exclusion filter drops, so the timeline stays focused on
  user actions and not status churn.

Excluded from this pass:

- PaymentMethodClass — cluster-scoped, operator-managed via Git; no
  user audit trail to surface.
- MeterDefinition, MonitoredResourceType — admin-managed.
- stripe.billing.miloapis.com/{StripeProviderConfig,
  StripePaymentMethod} — controller-owned, written exclusively under
  the system: actor and consumed by billing's user-facing PaymentMethod
  rather than directly by humans.
@mattdjenkinson mattdjenkinson marked this pull request as draft May 22, 2026 17:01
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