apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: secretpolicies.catalyst.openova.io
  labels:
    app.kubernetes.io/name: catalyst
    app.kubernetes.io/component: secret-policy
spec:
  group: catalyst.openova.io
  scope: Cluster
  names:
    kind: SecretPolicy
    listKind: SecretPolicyList
    singular: secretpolicy
    plural: secretpolicies
    shortNames:
      - secpol
      - secpols
    categories:
      - catalyst
      - openova
  versions:
    - name: v1
      served: true
      storage: true
      additionalPrinterColumns:
        - name: Rotations
          type: integer
          jsonPath: .status.rotationCount
        - name: NextDue
          type: string
          jsonPath: .status.nextRotationDue
          priority: 1
        - name: Age
          type: date
          jsonPath: .metadata.creationTimestamp
      subresources:
        status: {}
      schema:
        openAPIV3Schema:
          type: object
          description: |
            SecretPolicy declares which Secrets within an Environment
            (or globally) must rotate on what schedule and what to do
            when a Secret exceeds its TTL.

            Phase-0 lands the schema; the SRE Lead and Security Lead
            populate the rotation list per Sovereign in EPIC-1 (#1096)
            follow-up work. The rotation engine itself (Reflector +
            ESO + a small Go reconciler) is out of scope until then —
            this CRD is the contract.

            See docs/EPICS-1-6-unified-design.md §3.2.6 and
            docs/SECURITY.md for credential lifecycle conventions.
          required: [spec]
          properties:
            spec:
              type: object
              properties:
                rotation:
                  type: array
                  description: List of rotation rules. Each rule targets a credential class via labelSelector.
                  items:
                    type: object
                    required: [kind, labelSelector, ttl]
                    properties:
                      kind:
                        type: string
                        description: |
                          Credential class — drives which rotation handler
                          is used. Common values: oauth-client-secret,
                          tls-cert, db-password, api-key, jwt-signer,
                          sealed-secret-master.
                      labelSelector:
                        type: object
                        description: K8s labelSelector matching the Secret(s) this rule applies to.
                        properties:
                          matchLabels:
                            type: object
                            additionalProperties:
                              type: string
                          matchExpressions:
                            type: array
                            items:
                              type: object
                              required: [key, operator]
                              properties:
                                key:
                                  type: string
                                operator:
                                  type: string
                                  enum: [In, NotIn, Exists, DoesNotExist]
                                values:
                                  type: array
                                  items:
                                    type: string
                        x-kubernetes-preserve-unknown-fields: true
                      ttl:
                        type: string
                        pattern: '^[0-9]+(s|m|h|d)$'
                        description: |
                          Lifetime — Secrets older than ttl trigger the
                          declared action. Examples: 24h, 30d, 90d.
                      action:
                        type: string
                        enum: [rotate, warn, block]
                        default: warn
                        description: |
                          rotate = automated rotation via the registered
                          handler. warn = alert only. block = refuse new
                          deployments referencing the expired Secret.
                      gracePeriod:
                        type: string
                        pattern: '^[0-9]+(s|m|h|d)$'
                        description: |
                          Optional grace window after ttl during which
                          old Secret remains valid. Common for tls-cert.
                      handlerRef:
                        type: object
                        description: Optional named reference to a custom rotation handler.
                        properties:
                          name:
                            type: string
                          namespace:
                            type: string
                        x-kubernetes-preserve-unknown-fields: true
              x-kubernetes-preserve-unknown-fields: true
            status:
              type: object
              properties:
                rotationCount:
                  type: integer
                  minimum: 0
                  description: Number of rotation rules in spec.rotation[].
                nextRotationDue:
                  type: string
                  format: date-time
                  description: Earliest upcoming TTL boundary across all matched Secrets.
                lastEvaluatedAt:
                  type: string
                  format: date-time
                conditions:
                  type: array
                  items:
                    type: object
                    required: [type, status]
                    properties:
                      type:
                        type: string
                      status:
                        type: string
                        enum: ["True", "False", "Unknown"]
                      reason:
                        type: string
                      message:
                        type: string
                      lastTransitionTime:
                        type: string
                        format: date-time
                observedGeneration:
                  type: integer
                  format: int64
              x-kubernetes-preserve-unknown-fields: true
