pepr 0.13.4 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -5
- package/commitlint.config.js +1 -0
- package/dist/cli.js +375 -204
- package/dist/controller.js +1 -1
- package/dist/lib/assets/deploy.d.ts.map +1 -1
- package/dist/lib/assets/destroy.d.ts +2 -0
- package/dist/lib/assets/destroy.d.ts.map +1 -0
- package/dist/lib/assets/index.d.ts +6 -5
- package/dist/lib/assets/index.d.ts.map +1 -1
- package/dist/lib/assets/networking.d.ts +6 -5
- package/dist/lib/assets/networking.d.ts.map +1 -1
- package/dist/lib/assets/pods.d.ts +84 -4
- package/dist/lib/assets/pods.d.ts.map +1 -1
- package/dist/lib/assets/rbac.d.ts +6 -4
- package/dist/lib/assets/rbac.d.ts.map +1 -1
- package/dist/lib/assets/store.d.ts +7 -0
- package/dist/lib/assets/store.d.ts.map +1 -0
- package/dist/lib/assets/webhooks.d.ts +2 -2
- package/dist/lib/assets/webhooks.d.ts.map +1 -1
- package/dist/lib/assets/yaml.d.ts.map +1 -1
- package/dist/lib/capability.d.ts +21 -4
- package/dist/lib/capability.d.ts.map +1 -1
- package/dist/lib/controller/index.d.ts +10 -0
- package/dist/lib/controller/index.d.ts.map +1 -0
- package/dist/lib/controller/store.d.ts +7 -0
- package/dist/lib/controller/store.d.ts.map +1 -0
- package/dist/lib/filter.d.ts +2 -2
- package/dist/lib/filter.d.ts.map +1 -1
- package/dist/lib/{k8s/types.d.ts → k8s.d.ts} +14 -25
- package/dist/lib/k8s.d.ts.map +1 -0
- package/dist/lib/metrics.d.ts +12 -12
- package/dist/lib/metrics.d.ts.map +1 -1
- package/dist/lib/module.d.ts +25 -4
- package/dist/lib/module.d.ts.map +1 -1
- package/dist/lib/mutate-processor.d.ts +3 -3
- package/dist/lib/mutate-processor.d.ts.map +1 -1
- package/dist/lib/mutate-request.d.ts +11 -10
- package/dist/lib/mutate-request.d.ts.map +1 -1
- package/dist/lib/storage.d.ts +56 -0
- package/dist/lib/storage.d.ts.map +1 -0
- package/dist/lib/tls.d.ts.map +1 -0
- package/dist/lib/types.d.ts +28 -48
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/validate-processor.d.ts +2 -2
- package/dist/lib/validate-processor.d.ts.map +1 -1
- package/dist/lib/validate-request.d.ts +9 -8
- package/dist/lib/validate-request.d.ts.map +1 -1
- package/dist/lib/watch-processor.d.ts +3 -0
- package/dist/lib/watch-processor.d.ts.map +1 -0
- package/dist/lib.d.ts +3 -7
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +484 -807
- package/dist/lib.js.map +4 -4
- package/package.json +20 -22
- package/src/lib/assets/deploy.ts +69 -127
- package/src/lib/assets/destroy.ts +33 -0
- package/src/lib/assets/index.ts +8 -14
- package/src/lib/assets/networking.ts +28 -5
- package/src/lib/assets/pods.ts +130 -11
- package/src/lib/assets/rbac.ts +42 -4
- package/src/lib/assets/store.ts +49 -0
- package/src/lib/assets/webhooks.ts +2 -2
- package/src/lib/assets/yaml.ts +13 -3
- package/src/lib/capability.ts +69 -14
- package/src/lib/{controller.ts → controller/index.ts} +25 -23
- package/src/lib/controller/store.ts +197 -0
- package/src/lib/filter.ts +2 -2
- package/src/lib/{k8s/types.ts → k8s.ts} +15 -26
- package/src/lib/metrics.ts +22 -38
- package/src/lib/module.ts +47 -10
- package/src/lib/mutate-processor.ts +6 -6
- package/src/lib/mutate-request.ts +18 -26
- package/src/lib/storage.ts +128 -0
- package/src/lib/types.ts +30 -53
- package/src/lib/validate-processor.ts +5 -4
- package/src/lib/validate-request.ts +15 -19
- package/src/lib/watch-processor.ts +55 -0
- package/src/lib.ts +4 -8
- package/src/templates/capabilities/hello-pepr.ts +54 -5
- package/src/templates/package.json +1 -0
- package/dist/lib/controller.d.ts +0 -10
- package/dist/lib/controller.d.ts.map +0 -1
- package/dist/lib/fetch.d.ts +0 -23
- package/dist/lib/fetch.d.ts.map +0 -1
- package/dist/lib/k8s/index.d.ts +0 -7
- package/dist/lib/k8s/index.d.ts.map +0 -1
- package/dist/lib/k8s/kinds.d.ts +0 -12
- package/dist/lib/k8s/kinds.d.ts.map +0 -1
- package/dist/lib/k8s/tls.d.ts.map +0 -1
- package/dist/lib/k8s/types.d.ts.map +0 -1
- package/dist/lib/k8s/upstream.d.ts +0 -4
- package/dist/lib/k8s/upstream.d.ts.map +0 -1
- package/jest.config.json +0 -4
- package/journey/before.ts +0 -21
- package/journey/k8s.ts +0 -100
- package/journey/pepr-build.ts +0 -69
- package/journey/pepr-deploy.ts +0 -174
- package/journey/pepr-dev.ts +0 -155
- package/journey/pepr-format.ts +0 -13
- package/journey/pepr-init.ts +0 -12
- package/src/lib/fetch.ts +0 -76
- package/src/lib/k8s/index.ts +0 -14
- package/src/lib/k8s/kinds.ts +0 -531
- package/src/lib/k8s/upstream.ts +0 -53
- /package/dist/lib/{k8s/tls.d.ts → tls.d.ts} +0 -0
- /package/src/lib/{k8s/tls.ts → tls.ts} +0 -0
package/dist/lib.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/lib.ts", "../src/lib/capability.ts", "../src/lib/
|
|
4
|
-
"sourcesContent": ["import * as k8s from \"@kubernetes/client-node\";\nimport { StatusCodes as fetchStatus } from \"http-status-codes\";\nimport * as R from \"ramda\";\nimport { Capability } from \"./lib/capability\";\nimport { fetch, fetchRaw } from \"./lib/fetch\";\nimport { RegisterKind, a } from \"./lib/k8s/index\";\nimport Log from \"./lib/logger\";\nimport { PeprModule } from \"./lib/module\";\nimport { PeprMutateRequest } from \"./lib/mutate-request\";\nimport { PeprValidateRequest } from \"./lib/validate-request\";\nimport * as PeprUtils from \"./lib/utils\";\n\n// Import type information for external packages\nimport type * as K8sTypes from \"@kubernetes/client-node\";\nimport type * as RTypes from \"ramda\";\n\nexport {\n a,\n /** PeprModule is used to setup a complete Pepr Module: `new PeprModule(cfg, {...capabilities})` */\n PeprModule,\n PeprMutateRequest,\n PeprValidateRequest,\n PeprUtils,\n RegisterKind,\n Capability,\n Log,\n R,\n fetch,\n fetchRaw,\n fetchStatus,\n k8s,\n\n // Export the imported type information for external packages\n RTypes,\n K8sTypes,\n};\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { pickBy } from \"ramda\";\n\nimport { isWatchMode, modelToGroupVersionKind } from \"./k8s/index\";\nimport { GroupVersionKind } from \"./k8s/types\";\nimport Log from \"./logger\";\nimport {\n Binding,\n BindingFilter,\n BindingWithName,\n CapabilityCfg,\n CapabilityExport,\n Event,\n GenericClass,\n MutateAction,\n MutateActionChain,\n ValidateAction,\n WhenSelector,\n} from \"./types\";\n\n/**\n * A capability is a unit of functionality that can be registered with the Pepr runtime.\n */\nexport class Capability implements CapabilityExport {\n #name: string;\n #description: string;\n #namespaces?: string[] | undefined;\n #bindings: Binding[] = [];\n\n get bindings() {\n return this.#bindings;\n }\n\n get name() {\n return this.#name;\n }\n\n get description() {\n return this.#description;\n }\n\n get namespaces() {\n return this.#namespaces || [];\n }\n\n constructor(cfg: CapabilityCfg) {\n this.#name = cfg.name;\n this.#description = cfg.description;\n this.#namespaces = cfg.namespaces;\n\n // Bind When() to this instance\n this.When = this.When.bind(this);\n\n Log.info(`Capability ${this.#name} registered`);\n Log.debug(cfg);\n }\n\n /**\n * The When method is used to register a capability action to be executed when a Kubernetes resource is\n * processed by Pepr. The action will be executed if the resource matches the specified kind and any\n * filters that are applied.\n *\n * @param model the KubernetesObject model to match\n * @param kind if using a custom KubernetesObject not available in `a.*`, specify the GroupVersionKind\n * @returns\n */\n When<T extends GenericClass>(model: T, kind?: GroupVersionKind): WhenSelector<T> {\n const matchedKind = modelToGroupVersionKind(model.name);\n\n // If the kind is not specified and the model is not a KubernetesObject, throw an error\n if (!matchedKind && !kind) {\n throw new Error(`Kind not specified for ${model.name}`);\n }\n\n const binding: Binding = {\n // If the kind is not specified, use the matched kind from the model\n kind: kind || matchedKind,\n event: Event.Any,\n filters: {\n name: \"\",\n namespaces: [],\n labels: {},\n annotations: {},\n },\n };\n\n const bindings = this.#bindings;\n const prefix = `${this.#name}: ${model.name}`;\n const commonChain = { WithLabel, WithAnnotation, Mutate, Validate };\n const isNotEmpty = (value: object) => Object.keys(value).length > 0;\n const log = (message: string, cbString: string) => {\n const filteredObj = pickBy(isNotEmpty, binding.filters);\n\n Log.info(`${message} configured for ${binding.event}`, prefix);\n Log.info(filteredObj, prefix);\n Log.debug(cbString, prefix);\n };\n\n function Validate(validateCallback: ValidateAction<T>): void {\n if (!isWatchMode) {\n log(\"Validate Action\", validateCallback.toString());\n\n // Push the binding to the list of bindings for this capability as a new BindingAction\n // with the callback function to preserve\n bindings.push({\n ...binding,\n isValidate: true,\n validateCallback,\n });\n }\n }\n\n function Mutate(mutateCallback: MutateAction<T>): MutateActionChain<T> {\n if (!isWatchMode) {\n log(\"Mutate Action\", mutateCallback.toString());\n\n // Push the binding to the list of bindings for this capability as a new BindingAction\n // with the callback function to preserve\n bindings.push({\n ...binding,\n isMutate: true,\n mutateCallback,\n });\n }\n\n // Now only allow adding actions to the same binding\n return { Validate };\n }\n\n function InNamespace(...namespaces: string[]): BindingWithName<T> {\n Log.debug(`Add namespaces filter ${namespaces}`, prefix);\n binding.filters.namespaces.push(...namespaces);\n return { ...commonChain, WithName };\n }\n\n function WithName(name: string): BindingFilter<T> {\n Log.debug(`Add name filter ${name}`, prefix);\n binding.filters.name = name;\n return commonChain;\n }\n\n function WithLabel(key: string, value = \"\"): BindingFilter<T> {\n Log.debug(`Add label filter ${key}=${value}`, prefix);\n binding.filters.labels[key] = value;\n return commonChain;\n }\n\n function WithAnnotation(key: string, value = \"\"): BindingFilter<T> {\n Log.debug(`Add annotation filter ${key}=${value}`, prefix);\n binding.filters.annotations[key] = value;\n return commonChain;\n }\n\n function bindEvent(event: Event) {\n binding.event = event;\n return {\n ...commonChain,\n InNamespace,\n WithName,\n };\n }\n\n return {\n IsCreatedOrUpdated: () => bindEvent(Event.CreateOrUpdate),\n IsCreated: () => bindEvent(Event.Create),\n IsUpdated: () => bindEvent(Event.Update),\n IsDeleted: () => bindEvent(Event.Delete),\n };\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\n/** a is a collection of K8s types to be used within an action: `When(a.Configmap)` */\nexport {\n V1APIService as APIService,\n V1CertificateSigningRequest as CertificateSigningRequest,\n V1ClusterRole as ClusterRole,\n V1ClusterRoleBinding as ClusterRoleBinding,\n V1ConfigMap as ConfigMap,\n V1ControllerRevision as ControllerRevision,\n V1CronJob as CronJob,\n V1CSIDriver as CSIDriver,\n V1CSIStorageCapacity as CSIStorageCapacity,\n V1CustomResourceDefinition as CustomResourceDefinition,\n V1DaemonSet as DaemonSet,\n V1Deployment as Deployment,\n V1EndpointSlice as EndpointSlice,\n V1HorizontalPodAutoscaler as HorizontalPodAutoscaler,\n V1Ingress as Ingress,\n V1IngressClass as IngressClass,\n V1Job as Job,\n V1LimitRange as LimitRange,\n V1LocalSubjectAccessReview as LocalSubjectAccessReview,\n V1MutatingWebhookConfiguration as MutatingWebhookConfiguration,\n V1Namespace as Namespace,\n V1NetworkPolicy as NetworkPolicy,\n V1Node as Node,\n V1PersistentVolume as PersistentVolume,\n V1PersistentVolumeClaim as PersistentVolumeClaim,\n V1Pod as Pod,\n V1PodDisruptionBudget as PodDisruptionBudget,\n V1PodTemplate as PodTemplate,\n V1ReplicaSet as ReplicaSet,\n V1ReplicationController as ReplicationController,\n V1ResourceQuota as ResourceQuota,\n V1Role as Role,\n V1RoleBinding as RoleBinding,\n V1RuntimeClass as RuntimeClass,\n V1Secret as Secret,\n V1SelfSubjectAccessReview as SelfSubjectAccessReview,\n V1SelfSubjectRulesReview as SelfSubjectRulesReview,\n V1Service as Service,\n V1ServiceAccount as ServiceAccount,\n V1StatefulSet as StatefulSet,\n V1StorageClass as StorageClass,\n V1SubjectAccessReview as SubjectAccessReview,\n V1TokenReview as TokenReview,\n V1ValidatingWebhookConfiguration as ValidatingWebhookConfiguration,\n V1VolumeAttachment as VolumeAttachment,\n} from \"@kubernetes/client-node\";\n\nexport { GenericKind } from \"./types\";\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { KubernetesListObject, KubernetesObject, V1ObjectMeta } from \"@kubernetes/client-node\";\n\nexport { KubernetesListObject, KubernetesObject };\n\nexport enum Operation {\n CREATE = \"CREATE\",\n UPDATE = \"UPDATE\",\n DELETE = \"DELETE\",\n CONNECT = \"CONNECT\",\n}\n\n/**\n * GenericKind is a generic Kubernetes object that can be used to represent any Kubernetes object\n * that is not explicitly supported by Pepr. This can be used on its own or as a base class for\n * other types. See the examples in `HelloPepr.ts` for more information.\n */\nexport class GenericKind {\n apiVersion?: string;\n kind?: string;\n metadata?: V1ObjectMeta;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any;\n}\n\n/**\n * GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion\n * to avoid automatic coercion. It doesn't use a GroupVersion to avoid custom marshalling\n **/\nexport interface GroupVersionKind {\n /** The K8s resource kind, e..g \"Pod\". */\n readonly kind: string;\n readonly group: string;\n readonly version?: string;\n /** Optional, override the plural name for use in Webhook rules generation */\n readonly plural?: string;\n}\n\n/**\n * GroupVersionResource unambiguously identifies a resource. It doesn't anonymously include GroupVersion\n * to avoid automatic coercion. It doesn't use a GroupVersion to avoid custom marshalling\n */\nexport interface GroupVersionResource {\n readonly group: string;\n readonly version: string;\n readonly resource: string;\n}\n\n/**\n * A Kubernetes admission request to be processed by a capability.\n */\nexport interface Request<T = KubernetesObject> {\n /** UID is an identifier for the individual request/response. */\n readonly uid: string;\n\n /** Kind is the fully-qualified type of object being submitted (for example, v1.Pod or autoscaling.v1.Scale) */\n readonly kind: GroupVersionKind;\n\n /** Resource is the fully-qualified resource being requested (for example, v1.pods) */\n readonly resource: GroupVersionResource;\n\n /** SubResource is the sub-resource being requested, if any (for example, \"status\" or \"scale\") */\n readonly subResource?: string;\n\n /** RequestKind is the fully-qualified type of the original API request (for example, v1.Pod or autoscaling.v1.Scale). */\n readonly requestKind?: GroupVersionKind;\n\n /** RequestResource is the fully-qualified resource of the original API request (for example, v1.pods). */\n readonly requestResource?: GroupVersionResource;\n\n /** RequestSubResource is the sub-resource of the original API request, if any (for example, \"status\" or \"scale\"). */\n readonly requestSubResource?: string;\n\n /**\n * Name is the name of the object as presented in the request. On a CREATE operation, the client may omit name and\n * rely on the server to generate the name. If that is the case, this method will return the empty string.\n */\n readonly name: string;\n\n /** Namespace is the namespace associated with the request (if any). */\n readonly namespace?: string;\n\n /**\n * Operation is the operation being performed. This may be different than the operation\n * requested. e.g. a patch can result in either a CREATE or UPDATE Operation.\n */\n readonly operation: Operation;\n\n /** UserInfo is information about the requesting user */\n readonly userInfo: {\n /** The name that uniquely identifies this user among all active users. */\n username?: string;\n\n /**\n * A unique value that identifies this user across time. If this user is deleted\n * and another user by the same name is added, they will have different UIDs.\n */\n uid?: string;\n\n /** The names of groups this user is a part of. */\n groups?: string[];\n\n /** Any additional information provided by the authenticator. */\n extra?: {\n [key: string]: string[];\n };\n };\n\n /** Object is the object from the incoming request prior to default values being applied */\n readonly object: T;\n\n /** OldObject is the existing object. Only populated for UPDATE or DELETE requests. */\n readonly oldObject?: T;\n\n /** DryRun indicates that modifications will definitely not be persisted for this request. Defaults to false. */\n readonly dryRun?: boolean;\n\n /**\n * Options contains the options for the operation being performed.\n * e.g. `meta.k8s.io/v1.DeleteOptions` or `meta.k8s.io/v1.CreateOptions`. This may be\n * different than the options the caller provided. e.g. for a patch request the performed\n * Operation might be a CREATE, in which case the Options will a\n * `meta.k8s.io/v1.CreateOptions` even though the caller provided `meta.k8s.io/v1.PatchOptions`.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly options?: any;\n}\n\nexport interface MutateResponse {\n /** UID is an identifier for the individual request/response. This must be copied over from the corresponding AdmissionRequest. */\n uid: string;\n\n /** Allowed indicates whether or not the admission request was permitted. */\n allowed: boolean;\n\n /** Result contains extra details into why an admission request was denied. This field IS NOT consulted in any way if \"Allowed\" is \"true\". */\n result?: string;\n\n /** The patch body. Currently we only support \"JSONPatch\" which implements RFC 6902. */\n patch?: string;\n\n /** The type of Patch. Currently we only allow \"JSONPatch\". */\n patchType?: \"JSONPatch\";\n\n /**\n * AuditAnnotations is an unstructured key value map set by remote admission controller (e.g. error=image-blacklisted).\n *\n * See https://kubernetes.io/docs/reference/labels-annotations-taints/audit-annotations/ for more information\n */\n auditAnnotations?: {\n [key: string]: string;\n };\n\n /** warnings is a list of warning messages to return to the requesting API client. */\n warnings?: string[];\n}\n\nexport interface ValidateResponse extends MutateResponse {\n /** Status contains extra details into why an admission request was denied. This field IS NOT consulted in any way if \"Allowed\" is \"true\". */\n status?: {\n /** A machine-readable description of why this operation is in the\n \"Failure\" status. If this value is empty there is no information available. */\n code: number;\n\n /** A human-readable description of the status of this operation. */\n message: string;\n };\n}\n\nexport type WebhookIgnore = {\n /**\n * List of Kubernetes namespaces to always ignore.\n * Any resources in these namespaces will be ignored by Pepr.\n *\n * Note: `kube-system` and `pepr-system` are always ignored.\n */\n namespaces?: string[];\n /**\n * List of Kubernetes labels to always ignore.\n * Any resources with these labels will be ignored by Pepr.\n *\n * The example below will ignore any resources with the label `my-label=ulta-secret`:\n * ```\n * alwaysIgnore:\n * labels: [{ \"my-label\": \"ultra-secret\" }]\n * ```\n */\n labels?: Record<string, string>[];\n};\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { GenericClass } from \"../types\";\nimport { GroupVersionKind } from \"./types\";\n\nexport const gvkMap: Record<string, GroupVersionKind> = {\n /**\n * Represents a K8s ClusterRole resource.\n * ClusterRole is a set of permissions that can be bound to a user or group in a cluster-wide scope.\n * @see {@link https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole}\n */\n V1ClusterRole: {\n kind: \"ClusterRole\",\n version: \"v1\",\n group: \"rbac.authorization.k8s.io\",\n },\n /**\n * Represents a K8s ClusterRoleBinding resource.\n * ClusterRoleBinding binds a ClusterRole to a user or group in a cluster-wide scope.\n * @see {@link https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding}\n */\n V1ClusterRoleBinding: {\n kind: \"ClusterRoleBinding\",\n version: \"v1\",\n group: \"rbac.authorization.k8s.io\",\n },\n /**\n * Represents a K8s Role resource.\n * Role is a set of permissions that can be bound to a user or group in a namespace scope.\n * @see {@link https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole}\n */\n V1Role: {\n kind: \"Role\",\n version: \"v1\",\n group: \"rbac.authorization.k8s.io\",\n },\n /**\n * Represents a K8s RoleBinding resource.\n * RoleBinding binds a Role to a user or group in a namespace scope.\n * @see {@link https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding}\n */\n V1RoleBinding: {\n kind: \"RoleBinding\",\n version: \"v1\",\n group: \"rbac.authorization.k8s.io\",\n },\n /**\n * Represents a K8s ConfigMap resource.\n * ConfigMap holds configuration data for pods to consume.\n * @see {@link https://kubernetes.io/docs/concepts/configuration/configmap/}\n */\n V1ConfigMap: {\n kind: \"ConfigMap\",\n version: \"v1\",\n group: \"\",\n },\n\n /**\n * Represents a K8s Endpoints resource.\n * Endpoints expose a service's IP addresses and ports to other resources.\n * @see {@link https://kubernetes.io/docs/concepts/services-networking/service/#endpoints}\n */\n V1Endpoint: {\n kind: \"Endpoints\",\n version: \"v1\",\n group: \"\",\n plural: \"endpoints\",\n },\n\n /**\n * Represents a K8s LimitRange resource.\n * LimitRange enforces constraints on the resource consumption of objects in a namespace.\n * @see {@link https://kubernetes.io/docs/concepts/policy/limit-range/}\n */\n V1LimitRange: {\n kind: \"LimitRange\",\n version: \"v1\",\n group: \"\",\n },\n\n /**\n * Represents a K8s Namespace resource.\n * Namespace is a way to divide cluster resources between multiple users.\n * @see {@link https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/}\n */\n V1Namespace: {\n kind: \"Namespace\",\n version: \"v1\",\n group: \"\",\n },\n\n /**\n * Represents a K8s Node resource.\n * Node is a worker machine in Kubernetes.\n * @see {@link https://kubernetes.io/docs/concepts/architecture/nodes/}\n */\n V1Node: {\n kind: \"Node\",\n version: \"v1\",\n group: \"\",\n },\n\n /**\n * Represents a K8s PersistentVolumeClaim resource.\n * PersistentVolumeClaim is a user's request for and claim to a persistent volume.\n * @see {@link https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims}\n */\n V1PersistentVolumeClaim: {\n kind: \"PersistentVolumeClaim\",\n version: \"v1\",\n group: \"\",\n },\n\n /**\n * Represents a K8s PersistentVolume resource.\n * PersistentVolume is a piece of storage in the cluster that has been provisioned by an administrator.\n * @see {@link https://kubernetes.io/docs/concepts/storage/persistent-volumes/}\n */\n V1PersistentVolume: {\n kind: \"PersistentVolume\",\n version: \"v1\",\n group: \"\",\n },\n\n /**\n * Represents a K8s Pod resource.\n * Pod is the smallest and simplest unit in the Kubernetes object model.\n * @see {@link https://kubernetes.io/docs/concepts/workloads/pods/}\n */\n V1Pod: {\n kind: \"Pod\",\n version: \"v1\",\n group: \"\",\n },\n /**\n * Represents a K8s PodTemplate resource.\n * PodTemplate is an object that describes the pod that will be created from a higher level abstraction.\n * @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/#pod-template}\n */\n V1PodTemplate: {\n kind: \"PodTemplate\",\n version: \"v1\",\n group: \"\",\n },\n\n /**\n * Represents a K8s ReplicationController resource.\n * ReplicationController ensures that a specified number of pod replicas are running at any given time.\n * @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/}\n */\n V1ReplicationController: {\n kind: \"ReplicationController\",\n version: \"v1\",\n group: \"\",\n },\n\n /**\n * Represents a K8s ResourceQuota resource.\n * ResourceQuota provides constraints that limit resource consumption per namespace.\n * @see {@link https://kubernetes.io/docs/concepts/policy/resource-quotas/}\n */\n V1ResourceQuota: {\n kind: \"ResourceQuota\",\n version: \"v1\",\n group: \"\",\n },\n\n /**\n * Represents a K8s Secret resource.\n * Secret holds secret data of a certain type.\n * @see {@link https://kubernetes.io/docs/concepts/configuration/secret/}\n */\n V1Secret: {\n kind: \"Secret\",\n version: \"v1\",\n group: \"\",\n },\n\n /**\n * Represents a K8s ServiceAccount resource.\n * ServiceAccount is an identity that processes in a pod can use to access the Kubernetes API.\n * @see {@link https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/}\n */\n V1ServiceAccount: {\n kind: \"ServiceAccount\",\n version: \"v1\",\n group: \"\",\n },\n\n /**\n * Represents a K8s Service resource.\n * Service is an abstraction which defines a logical set of Pods and a policy by which to access them.\n * @see {@link https://kubernetes.io/docs/concepts/services-networking/service/}\n */\n V1Service: {\n kind: \"Service\",\n version: \"v1\",\n group: \"\",\n },\n\n /**\n * Represents a K8s MutatingWebhookConfiguration resource.\n * MutatingWebhookConfiguration configures a mutating admission webhook.\n * @see {@link https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#configure-admission-webhooks-on-the-fly}\n */\n V1MutatingWebhookConfiguration: {\n kind: \"MutatingWebhookConfiguration\",\n version: \"v1\",\n group: \"admissionregistration.k8s.io\",\n },\n\n /**\n * Represents a K8s ValidatingWebhookConfiguration resource.\n * ValidatingWebhookConfiguration configures a validating admission webhook.\n * @see {@link https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#configure-admission-webhooks-on-the-fly}\n */\n V1ValidatingWebhookConfiguration: {\n kind: \"ValidatingWebhookConfiguration\",\n version: \"v1\",\n group: \"admissionregistration.k8s.io\",\n },\n /**\n * Represents a K8s CustomResourceDefinition resource.\n * CustomResourceDefinition is a custom resource in a Kubernetes cluster.\n * @see {@link https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/}\n */\n V1CustomResourceDefinition: {\n kind: \"CustomResourceDefinition\",\n version: \"v1\",\n group: \"apiextensions.k8s.io\",\n },\n\n /**\n * Represents a K8s APIService resource.\n * APIService represents a server for a particular API version and group.\n * @see {@link https://kubernetes.io/docs/tasks/access-kubernetes-api/setup-extension-api-server/}\n */\n V1APIService: {\n kind: \"APIService\",\n version: \"v1\",\n group: \"apiregistration.k8s.io\",\n },\n\n /**\n * Represents a K8s ControllerRevision resource.\n * ControllerRevision is used to manage the history of a StatefulSet or DaemonSet.\n * @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#revision-history}\n */\n V1ControllerRevision: {\n kind: \"ControllerRevision\",\n version: \"v1\",\n group: \"apps\",\n },\n\n /**\n * Represents a K8s DaemonSet resource.\n * DaemonSet ensures that all (or some) nodes run a copy of a Pod.\n * @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/}\n */\n V1DaemonSet: {\n kind: \"DaemonSet\",\n version: \"v1\",\n group: \"apps\",\n },\n\n /**\n * Represents a K8s Deployment resource.\n * Deployment provides declarative updates for Pods and ReplicaSets.\n * @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/deployment/}\n */\n V1Deployment: {\n kind: \"Deployment\",\n version: \"v1\",\n group: \"apps\",\n },\n\n /**\n * Represents a K8s ReplicaSet resource.\n * ReplicaSet ensures that a specified number of pod replicas are running at any given time.\n * @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/}\n */\n V1ReplicaSet: {\n kind: \"ReplicaSet\",\n version: \"v1\",\n group: \"apps\",\n },\n\n /**\n * Represents a K8s StatefulSet resource.\n * StatefulSet is used to manage stateful applications.\n * @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/}\n */\n V1StatefulSet: {\n kind: \"StatefulSet\",\n version: \"v1\",\n group: \"apps\",\n },\n\n /**\n * Represents a K8s TokenReview resource.\n * TokenReview attempts to authenticate a token to a known user.\n * @see {@link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#tokenreview-v1-authentication-k8s-io}\n */\n V1TokenReview: {\n kind: \"TokenReview\",\n version: \"v1\",\n group: \"authentication.k8s.io\",\n },\n\n /**\n * Represents a K8s LocalSubjectAccessReview resource.\n * LocalSubjectAccessReview checks whether a specific user can perform a specific action in a specific namespace.\n * @see {@link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#localsubjectaccessreview-v1-authorization-k8s-io}\n */\n V1LocalSubjectAccessReview: {\n kind: \"LocalSubjectAccessReview\",\n version: \"v1\",\n group: \"authorization.k8s.io\",\n },\n\n /**\n * Represents a K8s SelfSubjectAccessReview resource.\n * SelfSubjectAccessReview checks whether the current user can perform a specific action.\n * @see {@link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#selfsubjectaccessreview-v1-authorization-k8s-io}\n */\n V1SelfSubjectAccessReview: {\n kind: \"SelfSubjectAccessReview\",\n version: \"v1\",\n group: \"authorization.k8s.io\",\n },\n\n /**\n * Represents a K8s SelfSubjectRulesReview resource.\n * SelfSubjectRulesReview lists the permissions a specific user has within a namespace.\n * @see {@link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#selfsubjectrulesreview-v1-authorization-k8s-io}\n */\n V1SelfSubjectRulesReview: {\n kind: \"SelfSubjectRulesReview\",\n version: \"v1\",\n group: \"authorization.k8s.io\",\n },\n\n /**\n * Represents a K8s SubjectAccessReview resource.\n * SubjectAccessReview checks whether a specific user can perform a specific action.\n * @see {@link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#subjectaccessreview-v1-authorization-k8s-io}\n */\n V1SubjectAccessReview: {\n kind: \"SubjectAccessReview\",\n version: \"v1\",\n group: \"authorization.k8s.io\",\n },\n\n /**\n * Represents a K8s HorizontalPodAutoscaler resource.\n * HorizontalPodAutoscaler automatically scales the number of Pods in a replication controller, deployment, or replica set.\n * @see {@link https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/}\n */\n V1HorizontalPodAutoscaler: {\n kind: \"HorizontalPodAutoscaler\",\n version: \"v2\",\n group: \"autoscaling\",\n },\n\n /**\n * Represents a K8s CronJob resource.\n * CronJob manages time-based jobs, specifically those that run periodically and complete after a successful execution.\n * @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/}\n */\n V1CronJob: {\n kind: \"CronJob\",\n version: \"v1\",\n group: \"batch\",\n },\n\n /**\n * Represents a K8s Job resource.\n * Job represents the configuration of a single job.\n * @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/job/}\n */\n V1Job: {\n kind: \"Job\",\n version: \"v1\",\n group: \"batch\",\n },\n\n /**\n * Represents a K8s CertificateSigningRequest resource.\n * CertificateSigningRequest represents a certificate signing request.\n * @see {@link https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/}\n */\n V1CertificateSigningRequest: {\n kind: \"CertificateSigningRequest\",\n version: \"v1\",\n group: \"certificates.k8s.io\",\n },\n\n /**\n * Represents a K8s EndpointSlice resource.\n * EndpointSlice represents a scalable set of network endpoints for a Kubernetes Service.\n * @see {@link https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/}\n */\n V1EndpointSlice: {\n kind: \"EndpointSlice\",\n version: \"v1\",\n group: \"discovery.k8s.io\",\n },\n\n /**\n * Represents a K8s IngressClass resource.\n * IngressClass represents the class of the Ingress, referenced by the Ingress spec.\n * @see {@link https://kubernetes.io/docs/concepts/services-networking/ingress/}\n */\n V1IngressClass: {\n kind: \"IngressClass\",\n version: \"v1\",\n group: \"networking.k8s.io\",\n },\n\n /**\n * Represents a K8s Ingress resource.\n * Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster.\n * @see {@link https://kubernetes.io/docs/concepts/services-networking/ingress/}\n */\n V1Ingress: {\n kind: \"Ingress\",\n version: \"v1\",\n group: \"networking.k8s.io\",\n plural: \"ingresses\",\n },\n\n /**\n * Represents a K8s NetworkPolicy resource.\n * NetworkPolicy defines a set of rules for how pods communicate with each other.\n * @see {@link https://kubernetes.io/docs/concepts/services-networking/network-policies/}\n */\n V1NetworkPolicy: {\n kind: \"NetworkPolicy\",\n version: \"v1\",\n group: \"networking.k8s.io\",\n },\n\n /**\n * Represents a K8s RuntimeClass resource.\n * RuntimeClass is a cluster-scoped resource that surfaces container runtime properties to the control plane.\n * @see {@link https://kubernetes.io/docs/concepts/containers/runtime-class/}\n */\n V1RuntimeClass: {\n kind: \"RuntimeClass\",\n version: \"v1\",\n group: \"node.k8s.io\",\n },\n\n /**\n * Represents a K8s PodDisruptionBudget resource.\n * PodDisruptionBudget is an API object that limits the number of pods of a replicated application that are down simultaneously.\n * @see {@link https://kubernetes.io/docs/concepts/workloads/pods/disruptions/}\n */\n V1PodDisruptionBudget: {\n kind: \"PodDisruptionBudget\",\n version: \"v1\",\n group: \"policy\",\n },\n\n /**\n * Represents a K8s VolumeAttachment resource.\n * VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node.\n * @see {@link https://kubernetes.io/docs/concepts/storage/storage-classes/}\n */\n V1VolumeAttachment: {\n kind: \"VolumeAttachment\",\n version: \"v1\",\n group: \"storage.k8s.io\",\n },\n\n /**\n * Represents a K8s CSIDriver resource.\n * CSIDriver captures information about a Container Storage Interface (CSI) volume driver.\n * @see {@link https://kubernetes.io/docs/concepts/storage/volumes/}\n */\n V1CSIDriver: {\n kind: \"CSIDriver\",\n version: \"v1\",\n group: \"storage.k8s.io\",\n },\n\n /**\n * Represents a K8s CSIStorageCapacity resource.\n * CSIStorageCapacity stores the reported storage capacity of a CSI node or storage class.\n * @see {@link https://kubernetes.io/docs/concepts/storage/csi/}\n */\n V1CSIStorageCapacity: {\n kind: \"CSIStorageCapacity\",\n version: \"v1\",\n group: \"storage.k8s.io\",\n },\n\n /**\n * Represents a K8s StorageClass resource.\n * StorageClass is a cluster-scoped resource that provides a way for administrators to describe the classes of storage they offer.\n * @see {@link https://kubernetes.io/docs/concepts/storage/storage-classes/}\n */\n V1StorageClass: {\n kind: \"StorageClass\",\n version: \"v1\",\n group: \"storage.k8s.io\",\n },\n};\n\nexport function modelToGroupVersionKind(key: string): GroupVersionKind {\n return gvkMap[key];\n}\n\n/**\n * Registers a new model and GroupVersionKind with Pepr for use with `When(a.<Kind>)`\n *\n * @param model Used to match the GroupVersionKind and define the type-data for the request\n * @param groupVersionKind Contains the match parameters to determine the request should be handled\n */\nexport const RegisterKind = (model: GenericClass, groupVersionKind: GroupVersionKind) => {\n const name = model.name;\n\n // Do not allow overwriting existing GVKs\n if (gvkMap[name]) {\n throw new Error(`GVK ${name} already registered`);\n }\n\n // Set the GVK\n gvkMap[name] = groupVersionKind;\n};\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\n// Export kinds as a single object\nimport * as kind from \"./upstream\";\n/** a is a collection of K8s types to be used within a action: `When(a.Configmap)` */\nexport { kind as a };\n\nexport { modelToGroupVersionKind, gvkMap, RegisterKind } from \"./kinds\";\n\n// If the hostname is pepr-static-test-watcher-0, then we are running in watch mode\nexport const isWatchMode = process.env.PEPR_WATCH_MODE === \"true\";\n\nexport * from \"./types\";\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { pino } from \"pino\";\n\nconst isPrettyLog = process.env.PEPR_PRETTY_LOGS === \"true\";\n\nconst pretty = {\n target: \"pino-pretty\",\n options: {\n colorize: true,\n },\n};\n\nconst transport = isPrettyLog ? pretty : undefined;\n\nconst Log = pino({\n transport,\n});\n\nif (process.env.LOG_LEVEL) {\n Log.level = process.env.LOG_LEVEL;\n}\n\nexport default Log;\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { StatusCodes } from \"http-status-codes\";\nimport f, { FetchError, RequestInfo, RequestInit } from \"node-fetch\";\nimport logger from \"./logger\";\n\nexport const fetchRaw = f;\n\nexport type FetchResponse<T> = {\n data: T;\n ok: boolean;\n status: number;\n statusText: string;\n};\n\n/**\n * Perform an async HTTP call and return the parsed JSON response, optionally\n * as a specific type.\n *\n * @example\n * ```ts\n * fetch<string[]>(\"https://example.com/api/foo\");\n * ```\n *\n * @param url The URL or Request object to fetch\n * @param init Additional options for the request\n * @returns\n */\nexport async function fetch<T>(url: URL | RequestInfo, init?: RequestInit): Promise<FetchResponse<T>> {\n let data = undefined as unknown as T;\n try {\n logger.debug(init, `Fetching ${url}`);\n\n const resp = await fetchRaw(url, init);\n const contentType = resp.headers.get(\"content-type\") || \"\";\n\n if (resp.ok) {\n // Parse the response as JSON if the content type is JSON\n if (contentType.includes(\"application/json\")) {\n data = await resp.json();\n } else {\n // Otherwise, return however the response was read\n data = (await resp.text()) as unknown as T;\n }\n }\n\n return {\n data,\n ok: resp.ok,\n status: resp.status,\n statusText: resp.statusText,\n };\n } catch (e) {\n if (e instanceof FetchError) {\n logger.debug(`Fetch failed: ${e instanceof Error ? e.message : e}`);\n\n // Parse the error code from the FetchError or default to 400 (Bad Request)\n const status = parseInt(e.code || \"400\");\n\n return {\n data,\n ok: false,\n status,\n statusText: e.message,\n };\n }\n\n return {\n data,\n ok: false,\n status: StatusCodes.BAD_REQUEST,\n statusText: \"Unknown error\",\n };\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { clone } from \"ramda\";\n\nimport { Capability } from \"./capability\";\nimport { Controller } from \"./controller\";\nimport { ValidateError } from \"./errors\";\nimport { MutateResponse, Request, ValidateResponse } from \"./k8s/types\";\nimport { CapabilityExport, ModuleConfig } from \"./types\";\n\nexport type PackageJSON = {\n description: string;\n pepr: ModuleConfig;\n};\n\nexport type PeprModuleOptions = {\n deferStart?: boolean;\n\n /** A user-defined callback to pre-process or intercept a Pepr request from K8s immediately before it is processed */\n beforeHook?: (req: Request) => void;\n\n /** A user-defined callback to post-process or intercept a Pepr response just before it is returned to K8s */\n afterHook?: (res: MutateResponse | ValidateResponse) => void;\n};\n\nexport class PeprModule {\n #controller!: Controller;\n\n /**\n * Create a new Pepr runtime\n *\n * @param config The configuration for the Pepr runtime\n * @param capabilities The capabilities to be loaded into the Pepr runtime\n * @param opts Options for the Pepr runtime\n */\n constructor({ description, pepr }: PackageJSON, capabilities: Capability[] = [], opts: PeprModuleOptions = {}) {\n const config: ModuleConfig = clone(pepr);\n config.description = description;\n\n // Need to validate at runtime since TS gets sad about parsing the package.json\n ValidateError(config.onError);\n\n // Bind public methods\n this.start = this.start.bind(this);\n\n // Handle build mode\n if (process.env.PEPR_MODE === \"build\" && process.send) {\n const exportedCapabilities: CapabilityExport[] = [];\n\n // Send capability map to parent process\n for (const capability of capabilities) {\n // Convert the capability to a capability config\n exportedCapabilities.push({\n name: capability.name,\n description: capability.description,\n namespaces: capability.namespaces,\n bindings: capability.bindings,\n });\n }\n\n process.send(exportedCapabilities);\n\n return;\n }\n\n this.#controller = new Controller(config, capabilities, opts.beforeHook, opts.afterHook);\n\n // Stop processing if deferStart is set to true\n if (opts.deferStart) {\n return;\n }\n\n this.start();\n }\n\n /**\n * Start the Pepr runtime manually.\n * Normally this is called automatically when the Pepr module is instantiated, but can be called manually if `deferStart` is set to `true` in the constructor.\n *\n * @param port\n */\n start(port = 3000) {\n this.#controller.startServer(port);\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport express, { NextFunction } from \"express\";\nimport fs from \"fs\";\nimport https from \"https\";\n\nimport { Capability } from \"./capability\";\nimport { isWatchMode } from \"./k8s\";\nimport { MutateResponse, Request, ValidateResponse } from \"./k8s/types\";\nimport Log from \"./logger\";\nimport { MetricsCollector } from \"./metrics\";\nimport { mutateProcessor } from \"./mutate-processor\";\nimport { ModuleConfig } from \"./types\";\nimport { validateProcessor } from \"./validate-processor\";\n\nexport class Controller {\n // Track whether the server is running\n #running = false;\n\n // Metrics collector\n #metricsCollector = new MetricsCollector(\"pepr\");\n\n // The token used to authenticate requests\n #token = \"\";\n\n // The express app instance\n readonly #app = express();\n\n // Initialized with the constructor\n readonly #config: ModuleConfig;\n readonly #capabilities: Capability[];\n readonly #beforeHook?: (req: Request) => void;\n readonly #afterHook?: (res: MutateResponse) => void;\n\n constructor(\n config: ModuleConfig,\n capabilities: Capability[],\n beforeHook?: (req: Request) => void,\n afterHook?: (res: MutateResponse) => void,\n ) {\n this.#config = config;\n this.#capabilities = capabilities;\n this.#beforeHook = beforeHook;\n this.#afterHook = afterHook;\n\n // Bind public methods\n this.startServer = this.startServer.bind(this);\n\n // Middleware for logging requests\n this.#app.use(Controller.#logger);\n\n // Middleware for parsing JSON, limit to 2mb vs 100K for K8s compatibility\n this.#app.use(express.json({ limit: \"2mb\" }));\n\n if (beforeHook) {\n Log.info(`Using beforeHook: ${beforeHook}`);\n }\n\n if (afterHook) {\n Log.info(`Using afterHook: ${afterHook}`);\n }\n\n // Bind endpoints\n this.#bindEndpoints();\n }\n\n /** Start the webhook server */\n startServer(port: number) {\n if (this.#running) {\n throw new Error(\"Cannot start Pepr module: Pepr module was not instantiated with deferStart=true\");\n }\n\n // Load SSL certificate and key\n const options = {\n key: fs.readFileSync(process.env.SSL_KEY_PATH || \"/etc/certs/tls.key\"),\n cert: fs.readFileSync(process.env.SSL_CERT_PATH || \"/etc/certs/tls.crt\"),\n };\n\n // Get the API token if not in watch mode\n if (!isWatchMode) {\n // Get the API token from the environment variable or the mounted secret\n this.#token = process.env.PEPR_API_TOKEN || fs.readFileSync(\"/app/api-token/value\").toString().trim();\n Log.info(`Using API token: ${this.#token}`);\n\n if (!this.#token) {\n throw new Error(\"API token not found\");\n }\n }\n\n // Create HTTPS server\n const server = https.createServer(options, this.#app).listen(port);\n\n // Handle server listening event\n server.on(\"listening\", () => {\n Log.info(`Server listening on port ${port}`);\n // Track that the server is running\n this.#running = true;\n });\n\n // Handle EADDRINUSE errors\n server.on(\"error\", (e: { code: string }) => {\n if (e.code === \"EADDRINUSE\") {\n Log.warn(\n `Address in use, retrying in 2 seconds. If this persists, ensure ${port} is not in use, e.g. \"lsof -i :${port}\"`,\n );\n setTimeout(() => {\n server.close();\n server.listen(port);\n }, 2000);\n }\n });\n\n // Listen for the SIGTERM signal and gracefully close the server\n process.on(\"SIGTERM\", () => {\n Log.info(\"Received SIGTERM, closing server\");\n server.close(() => {\n Log.info(\"Server closed\");\n process.exit(0);\n });\n });\n }\n\n #bindEndpoints = () => {\n // Health check endpoint\n this.#app.get(\"/healthz\", Controller.#healthz);\n\n // Metrics endpoint\n this.#app.get(\"/metrics\", this.#metrics);\n\n if (isWatchMode) {\n return;\n }\n\n // Require auth for webhook endpoints\n this.#app.use([\"/mutate/:token\", \"/validate/:token\"], this.#validateToken);\n\n // Mutate endpoint\n this.#app.post(\"/mutate/:token\", this.#admissionReq(\"Mutate\"));\n\n // Validate endpoint\n this.#app.post(\"/validate/:token\", this.#admissionReq(\"Validate\"));\n };\n\n /**\n * Validate the token in the request path\n *\n * @param req The incoming request\n * @param res The outgoing response\n * @param next The next middleware function\n * @returns\n */\n #validateToken = (req: express.Request, res: express.Response, next: NextFunction) => {\n // Validate the token\n const { token } = req.params;\n if (token !== this.#token) {\n const err = `Unauthorized: invalid token '${token.replace(/[^\\w]/g, \"_\")}'`;\n Log.warn(err);\n res.status(401).send(err);\n this.#metricsCollector.alert();\n return;\n }\n\n // Token is valid, continue\n next();\n };\n\n /**\n * Metrics endpoint handler\n *\n * @param req the incoming request\n * @param res the outgoing response\n */\n #metrics = async (req: express.Request, res: express.Response) => {\n try {\n res.send(await this.#metricsCollector.getMetrics());\n } catch (err) {\n Log.error(err);\n res.status(500).send(\"Internal Server Error\");\n }\n };\n\n /**\n * Admission request handler for both mutate and validate requests\n *\n * @param admissionKind the type of admission request\n * @returns the request handler\n */\n #admissionReq = (admissionKind: \"Mutate\" | \"Validate\") => {\n // Create the admission request handler\n return async (req: express.Request, res: express.Response) => {\n // Start the metrics timer\n const startTime = this.#metricsCollector.observeStart();\n\n try {\n // Get the request from the body or create an empty request\n const request: Request = req.body?.request || ({} as Request);\n\n // Run the before hook if it exists\n this.#beforeHook && this.#beforeHook(request || {});\n\n // Setup identifiers for logging\n const name = request?.name ? `/${request.name}` : \"\";\n const namespace = request?.namespace || \"\";\n const gvk = request?.kind || { group: \"\", version: \"\", kind: \"\" };\n\n const reqMetadata = {\n uid: request.uid,\n namespace,\n name,\n };\n\n Log.info({ ...reqMetadata, gvk, operation: request.operation, admissionKind }, \"Incoming request\");\n Log.debug({ ...reqMetadata, request }, \"Incoming request body\");\n\n // Process the request\n let response: MutateResponse | ValidateResponse;\n\n // Call mutate or validate based on the admission kind\n if (admissionKind === \"Mutate\") {\n response = await mutateProcessor(this.#config, this.#capabilities, request, reqMetadata);\n } else {\n response = await validateProcessor(this.#capabilities, request, reqMetadata);\n }\n\n // Run the after hook if it exists\n this.#afterHook && this.#afterHook(response);\n\n // Log the response\n Log.debug({ ...reqMetadata, response }, \"Outgoing response\");\n\n // Send a no prob bob response\n res.send({\n apiVersion: \"admission.k8s.io/v1\",\n kind: \"AdmissionReview\",\n response,\n });\n this.#metricsCollector.observeEnd(startTime, admissionKind);\n } catch (err) {\n Log.error(err);\n res.status(500).send(\"Internal Server Error\");\n this.#metricsCollector.error();\n }\n };\n };\n\n /**\n * Middleware for logging requests\n *\n * @param req the incoming request\n * @param res the outgoing response\n * @param next the next middleware function\n */\n static #logger(req: express.Request, res: express.Response, next: express.NextFunction) {\n const startTime = Date.now();\n\n res.on(\"finish\", () => {\n const elapsedTime = Date.now() - startTime;\n const message = {\n uid: req.body?.request?.uid,\n method: req.method,\n url: req.originalUrl,\n status: res.statusCode,\n duration: `${elapsedTime} ms`,\n };\n\n res.statusCode >= 300 ? Log.warn(message) : Log.info(message);\n });\n\n next();\n }\n /**\n * Health check endpoint handler\n *\n * @param req the incoming request\n * @param res the outgoing response\n */\n static #healthz(req: express.Request, res: express.Response) {\n try {\n res.send(\"OK\");\n } catch (err) {\n Log.error(err);\n res.status(500).send(\"Internal Server Error\");\n }\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\n/* eslint-disable class-methods-use-this */\n\nimport { performance } from \"perf_hooks\";\nimport promClient, { Counter, Registry, Summary } from \"prom-client\";\nimport Log from \"./logger\";\n\nconst loggingPrefix = \"MetricsCollector\";\n\ninterface MetricNames {\n errors: string;\n alerts: string;\n mutate: string;\n validate: string;\n}\n\ninterface MetricArgs {\n name: string;\n help: string;\n registers: Registry[];\n}\n\n/**\n * MetricsCollector class handles metrics collection using prom-client and performance hooks.\n */\nexport class MetricsCollector {\n #registry: Registry;\n #counters: Map<string, Counter<string>> = new Map();\n #summaries: Map<string, Summary<string>> = new Map();\n #prefix: string;\n\n #metricNames: MetricNames = {\n errors: \"errors\",\n alerts: \"alerts\",\n mutate: \"Mutate\",\n validate: \"Validate\",\n };\n\n /**\n * Creates a MetricsCollector instance with prefixed metrics.\n * @param [prefix='pepr'] - The prefix for the metric names.\n */\n constructor(prefix = \"pepr\") {\n this.#registry = new Registry();\n this.#prefix = prefix;\n this.addCounter(this.#metricNames.errors, \"Mutation/Validate errors encountered\");\n this.addCounter(this.#metricNames.alerts, \"Mutation/Validate bad api token received\");\n this.addSummary(this.#metricNames.mutate, \"Mutation operation summary\");\n this.addSummary(this.#metricNames.validate, \"Validation operation summary\");\n }\n\n #getMetricName(name: string) {\n return `${this.#prefix}_${name}`;\n }\n\n #addMetric<T extends Counter<string> | Summary<string>>(\n collection: Map<string, T>,\n MetricType: new (args: MetricArgs) => T,\n name: string,\n help: string,\n ) {\n if (collection.has(this.#getMetricName(name))) {\n Log.debug(`Metric for ${name} already exists`, loggingPrefix);\n return;\n }\n\n // Bind public methods\n this.incCounter = this.incCounter.bind(this);\n this.error = this.error.bind(this);\n this.alert = this.alert.bind(this);\n this.observeStart = this.observeStart.bind(this);\n this.observeEnd = this.observeEnd.bind(this);\n this.getMetrics = this.getMetrics.bind(this);\n\n const metric = new MetricType({\n name: this.#getMetricName(name),\n help,\n registers: [this.#registry],\n });\n\n collection.set(this.#getMetricName(name), metric);\n }\n\n addCounter(name: string, help: string) {\n this.#addMetric(this.#counters, promClient.Counter, name, help);\n }\n\n addSummary(name: string, help: string) {\n this.#addMetric(this.#summaries, promClient.Summary, name, help);\n }\n\n incCounter(name: string) {\n this.#counters.get(this.#getMetricName(name))?.inc();\n }\n\n /**\n * Increments the error counter.\n */\n error() {\n this.incCounter(this.#metricNames.errors);\n }\n\n /**\n * Increments the alerts counter.\n */\n alert() {\n this.incCounter(this.#metricNames.alerts);\n }\n\n /**\n * Returns the current timestamp from performance.now() method. Useful for start timing an operation.\n * @returns The timestamp.\n */\n observeStart() {\n return performance.now();\n }\n\n /**\n * Observes the duration since the provided start time and updates the summary.\n * @param startTime - The start time.\n * @param name - The metrics summary to increment.\n */\n observeEnd(startTime: number, name: string = this.#metricNames.mutate) {\n this.#summaries.get(this.#getMetricName(name))?.observe(performance.now() - startTime);\n }\n\n /**\n * Fetches the current metrics from the registry.\n * @returns The metrics.\n */\n async getMetrics() {\n return this.#registry.metrics();\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport jsonPatch from \"fast-json-patch\";\n\nimport { Capability } from \"./capability\";\nimport { Errors } from \"./errors\";\nimport { shouldSkipRequest } from \"./filter\";\nimport { MutateResponse, Request } from \"./k8s/types\";\nimport { Secret } from \"./k8s/upstream\";\nimport Log from \"./logger\";\nimport { PeprMutateRequest } from \"./mutate-request\";\nimport { ModuleConfig } from \"./types\";\nimport { base64Encode, convertFromBase64Map, convertToBase64Map } from \"./utils\";\n\nexport async function mutateProcessor(\n config: ModuleConfig,\n capabilities: Capability[],\n req: Request,\n reqMetadata: Record<string, string>,\n): Promise<MutateResponse> {\n const wrapped = new PeprMutateRequest(req);\n const response: MutateResponse = {\n uid: req.uid,\n warnings: [],\n allowed: false,\n };\n\n // Track whether any capability matched the request\n let matchedAction = false;\n\n // Track data fields that should be skipped during decoding\n let skipDecode: string[] = [];\n\n // If the resource is a secret, decode the data\n const isSecret = req.kind.version == \"v1\" && req.kind.kind == \"Secret\";\n if (isSecret) {\n skipDecode = convertFromBase64Map(wrapped.Raw as unknown as Secret);\n }\n\n Log.info(reqMetadata, `Processing request`);\n\n for (const { name, bindings, namespaces } of capabilities) {\n const actionMetadata = { ...reqMetadata, name };\n\n for (const action of bindings) {\n // Skip this action if it's not a mutate action\n if (!action.mutateCallback) {\n continue;\n }\n\n // Continue to the next action without doing anything if this one should be skipped\n if (shouldSkipRequest(action, req, namespaces)) {\n continue;\n }\n\n const label = action.mutateCallback.name;\n Log.info(actionMetadata, `Processing matched action ${label}`);\n\n matchedAction = true;\n\n // Add annotations to the request to indicate that the capability started processing\n // this will allow tracking of failed mutations that were permitted to continue\n const updateStatus = (status: string) => {\n // Only update the status if the request is a CREATE or UPDATE (we don't use CONNECT)\n if (req.operation == \"DELETE\") {\n return;\n }\n\n const identifier = `${config.uuid}.pepr.dev/${name}`;\n wrapped.Raw.metadata = wrapped.Raw.metadata || {};\n wrapped.Raw.metadata.annotations = wrapped.Raw.metadata.annotations || {};\n wrapped.Raw.metadata.annotations[identifier] = status;\n };\n\n updateStatus(\"started\");\n\n try {\n // Run the action\n await action.mutateCallback(wrapped);\n\n Log.info(actionMetadata, `Action succeeded`);\n\n // Add annotations to the request to indicate that the capability succeeded\n updateStatus(\"succeeded\");\n } catch (e) {\n Log.warn(actionMetadata, `Action failed: ${e}`);\n updateStatus(\"warning\");\n\n // Annoying ts false positive\n response.warnings = response.warnings || [];\n response.warnings.push(`Action failed: ${e}`);\n\n switch (config.onError) {\n case Errors.reject:\n Log.error(actionMetadata, `Action failed: ${e}`);\n response.result = \"Pepr module configured to reject on error\";\n return response;\n\n case Errors.audit:\n response.auditAnnotations = response.auditAnnotations || {};\n response.auditAnnotations[Date.now()] = e;\n break;\n }\n }\n }\n }\n\n // If we've made it this far, the request is allowed\n response.allowed = true;\n\n // If no capability matched the request, exit early\n if (!matchedAction) {\n Log.info(reqMetadata, `No matching actions found`);\n return response;\n }\n\n // delete operations can't be mutate, just return before the transformation\n if (req.operation == \"DELETE\") {\n return response;\n }\n\n const transformed = wrapped.Raw;\n\n // Post-process the Secret requests to convert it back to the original format\n if (isSecret) {\n convertToBase64Map(transformed as unknown as Secret, skipDecode);\n }\n\n // Compare the original request to the modified request to get the patches\n const patches = jsonPatch.compare(req.object, transformed);\n\n // Only add the patch if there are patches to apply\n if (patches.length > 0) {\n response.patchType = \"JSONPatch\";\n // Webhook must be base64-encoded\n // https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#response\n response.patch = base64Encode(JSON.stringify(patches));\n }\n\n // Remove the warnings array if it's empty\n if (response.warnings && response.warnings.length < 1) {\n delete response.warnings;\n }\n\n Log.debug({ ...reqMetadata, patches }, `Patches generated`);\n\n return response;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nexport const Errors = {\n audit: \"audit\",\n ignore: \"ignore\",\n reject: \"reject\",\n};\n\nexport const ErrorList = Object.values(Errors);\n\n/**\n * Validate the error or throw an error\n * @param error\n */\nexport function ValidateError(error = \"\") {\n if (!ErrorList.includes(error)) {\n throw new Error(`Invalid error: ${error}. Must be one of: ${ErrorList.join(\", \")}`);\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { Operation, Request } from \"./k8s/types\";\nimport logger from \"./logger\";\nimport { Binding, Event } from \"./types\";\n\n/**\n * shouldSkipRequest determines if a request should be skipped based on the binding filters.\n *\n * @param binding the action binding\n * @param req the incoming request\n * @returns\n */\nexport function shouldSkipRequest(binding: Binding, req: Request, capabilityNamespaces: string[]) {\n const { group, kind, version } = binding.kind || {};\n const { namespaces, labels, annotations, name } = binding.filters || {};\n const operation = req.operation.toUpperCase();\n // Use the old object if the request is a DELETE operation\n const srcObject = operation === Operation.DELETE ? req.oldObject : req.object;\n const { metadata } = srcObject || {};\n const combinedNamespaces = [...namespaces, ...capabilityNamespaces];\n\n // Test for matching operation\n if (!binding.event.includes(operation) && !binding.event.includes(Event.Any)) {\n return true;\n }\n\n // Test name first, since it's the most specific\n if (name && name !== req.name) {\n return true;\n }\n\n // Test for matching kinds\n if (kind !== req.kind.kind) {\n return true;\n }\n\n // Test for matching groups\n if (group && group !== req.kind.group) {\n return true;\n }\n\n // Test for matching versions\n if (version && version !== req.kind.version) {\n return true;\n }\n\n // Test for matching namespaces\n if (combinedNamespaces.length && !combinedNamespaces.includes(req.namespace || \"\")) {\n logger.debug(\"Namespace does not match\");\n return true;\n }\n\n // Test for matching labels\n for (const [key, value] of Object.entries(labels)) {\n const testKey = metadata?.labels?.[key];\n\n // First check if the label exists\n if (!testKey) {\n logger.debug(`Label ${key} does not exist`);\n return true;\n }\n\n // Then check if the value matches, if specified\n if (value && testKey !== value) {\n logger.debug(`${testKey} does not match ${value}`);\n return true;\n }\n }\n\n // Test for matching annotations\n for (const [key, value] of Object.entries(annotations)) {\n const testKey = metadata?.annotations?.[key];\n\n // First check if the annotation exists\n if (!testKey) {\n logger.debug(`Annotation ${key} does not exist`);\n return true;\n }\n\n // Then check if the value matches, if specified\n if (value && testKey !== value) {\n logger.debug(`${testKey} does not match ${value}`);\n return true;\n }\n }\n\n // No failed filters, so we should not skip this request\n return false;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { clone, mergeDeepRight } from \"ramda\";\n\nimport { KubernetesObject, Operation, Request } from \"./k8s/types\";\nimport { DeepPartial } from \"./types\";\n\n/**\n * The RequestWrapper class provides methods to modify Kubernetes objects in the context\n * of a mutating webhook request.\n */\nexport class PeprMutateRequest<T extends KubernetesObject> {\n Raw: T;\n\n #input: Request<T>;\n\n get PermitSideEffects() {\n return !this.#input.dryRun;\n }\n\n /**\n * Indicates whether the request is a dry run.\n * @returns true if the request is a dry run, false otherwise.\n */\n get IsDryRun() {\n return this.#input.dryRun;\n }\n\n /**\n * Provides access to the old resource in the request if available.\n * @returns The old Kubernetes resource object or null if not available.\n */\n get OldResource() {\n return this.#input.oldObject;\n }\n\n /**\n * Provides access to the request object.\n * @returns The request object containing the Kubernetes resource.\n */\n get Request() {\n return this.#input;\n }\n\n /**\n * Creates a new instance of the action class.\n * @param input - The request object containing the Kubernetes resource to modify.\n */\n constructor(input: Request<T>) {\n this.#input = input;\n\n // Bind public methods\n this.Merge = this.Merge.bind(this);\n this.SetLabel = this.SetLabel.bind(this);\n this.SetAnnotation = this.SetAnnotation.bind(this);\n this.RemoveLabel = this.RemoveLabel.bind(this);\n this.RemoveAnnotation = this.RemoveAnnotation.bind(this);\n this.HasLabel = this.HasLabel.bind(this);\n this.HasAnnotation = this.HasAnnotation.bind(this);\n\n // If this is a DELETE operation, use the oldObject instead\n if (input.operation.toUpperCase() === Operation.DELETE) {\n this.Raw = clone(input.oldObject as T);\n } else {\n // Otherwise, use the incoming object\n this.Raw = clone(input.object);\n }\n\n if (!this.Raw) {\n throw new Error(\"unable to load the request object into PeprRequest.RawP\");\n }\n }\n\n /**\n * Deep merges the provided object with the current resource.\n *\n * @param obj - The object to merge with the current resource.\n */\n Merge(obj: DeepPartial<T>) {\n this.Raw = mergeDeepRight(this.Raw, obj) as unknown as T;\n }\n\n /**\n * Updates a label on the Kubernetes resource.\n * @param key - The key of the label to update.\n * @param value - The value of the label.\n * @returns The current action instance for method chaining.\n */\n SetLabel(key: string, value: string) {\n const ref = this.Raw;\n\n ref.metadata = ref.metadata ?? {};\n ref.metadata.labels = ref.metadata.labels ?? {};\n ref.metadata.labels[key] = value;\n\n return this;\n }\n\n /**\n * Updates an annotation on the Kubernetes resource.\n * @param key - The key of the annotation to update.\n * @param value - The value of the annotation.\n * @returns The current action instance for method chaining.\n */\n SetAnnotation(key: string, value: string) {\n const ref = this.Raw;\n\n ref.metadata = ref.metadata ?? {};\n ref.metadata.annotations = ref.metadata.annotations ?? {};\n ref.metadata.annotations[key] = value;\n\n return this;\n }\n\n /**\n * Removes a label from the Kubernetes resource.\n * @param key - The key of the label to remove.\n * @returns The current Action instance for method chaining.\n */\n RemoveLabel(key: string) {\n if (this.Raw.metadata?.labels?.[key]) {\n delete this.Raw.metadata.labels[key];\n }\n\n return this;\n }\n\n /**\n * Removes an annotation from the Kubernetes resource.\n * @param key - The key of the annotation to remove.\n * @returns The current Action instance for method chaining.\n */\n RemoveAnnotation(key: string) {\n if (this.Raw.metadata?.annotations?.[key]) {\n delete this.Raw.metadata.annotations[key];\n }\n\n return this;\n }\n\n /**\n * Check if a label exists on the Kubernetes resource.\n *\n * @param key the label key to check\n * @returns\n */\n HasLabel(key: string) {\n return this.Raw.metadata?.labels?.[key] !== undefined;\n }\n\n /**\n * Check if an annotation exists on the Kubernetes resource.\n *\n * @param key the annotation key to check\n * @returns\n */\n HasAnnotation(key: string) {\n return this.Raw.metadata?.annotations?.[key] !== undefined;\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport Log from \"./logger\";\n\n/** Test if a string is ascii or not */\nexport const isAscii = /^[\\s\\x20-\\x7E]*$/;\n\n/**\n * Encode all ascii values in a map to base64\n * @param obj The object to encode\n * @param skip A list of keys to skip encoding\n */\nexport function convertToBase64Map(obj: { data?: Record<string, string> }, skip: string[]) {\n obj.data = obj.data ?? {};\n for (const key in obj.data) {\n const value = obj.data[key];\n // Only encode ascii values\n obj.data[key] = skip.includes(key) ? value : base64Encode(value);\n }\n}\n\n/**\n * Decode all ascii values in a map from base64 to utf-8\n * @param obj The object to decode\n * @returns A list of keys that were skipped\n */\nexport function convertFromBase64Map(obj: { data?: Record<string, string> }) {\n const skip: string[] = [];\n\n obj.data = obj.data ?? {};\n for (const key in obj.data) {\n if (obj.data[key] == undefined) {\n obj.data[key] = \"\";\n } else {\n const decoded = base64Decode(obj.data[key]);\n if (isAscii.test(decoded)) {\n // Only decode ascii values\n obj.data[key] = decoded;\n } else {\n skip.push(key);\n }\n }\n }\n Log.debug(`Non-ascii data detected in keys: ${skip}, skipping automatic base64 decoding`);\n return skip;\n}\n\n/** Decode a base64 string */\nexport function base64Decode(data: string) {\n return Buffer.from(data, \"base64\").toString(\"utf-8\");\n}\n\n/** Encode a string to base64 */\nexport function base64Encode(data: string) {\n return Buffer.from(data).toString(\"base64\");\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\n/* eslint-disable class-methods-use-this */\n\nimport { clone } from \"ramda\";\nimport { KubernetesObject, Operation, Request } from \"./k8s/types\";\nimport { ValidateResponse } from \"./types\";\n\n/**\n * The RequestWrapper class provides methods to modify Kubernetes objects in the context\n * of a mutating webhook request.\n */\nexport class PeprValidateRequest<T extends KubernetesObject> {\n Raw: T;\n\n #input: Request<T>;\n\n /**\n * Provides access to the old resource in the request if available.\n * @returns The old Kubernetes resource object or null if not available.\n */\n get OldResource() {\n return this.#input.oldObject;\n }\n\n /**\n * Provides access to the request object.\n * @returns The request object containing the Kubernetes resource.\n */\n get Request() {\n return this.#input;\n }\n\n /**\n * Creates a new instance of the Action class.\n * @param input - The request object containing the Kubernetes resource to modify.\n */\n constructor(input: Request<T>) {\n this.#input = input;\n\n // Bind public methods to this instance\n this.HasLabel = this.HasLabel.bind(this);\n this.HasAnnotation = this.HasAnnotation.bind(this);\n this.Approve = this.Approve.bind(this);\n this.Deny = this.Deny.bind(this);\n\n // If this is a DELETE operation, use the oldObject instead\n if (input.operation.toUpperCase() === Operation.DELETE) {\n this.Raw = clone(input.oldObject as T);\n } else {\n // Otherwise, use the incoming object\n this.Raw = clone(input.object);\n }\n\n if (!this.Raw) {\n throw new Error(\"unable to load the request object into PeprRequest.RawP\");\n }\n }\n\n /**\n * Check if a label exists on the Kubernetes resource.\n *\n * @param key the label key to check\n * @returns\n */\n HasLabel(key: string) {\n return this.Raw.metadata?.labels?.[key] !== undefined;\n }\n\n /**\n * Check if an annotation exists on the Kubernetes resource.\n *\n * @param key the annotation key to check\n * @returns\n */\n HasAnnotation(key: string) {\n return this.Raw.metadata?.annotations?.[key] !== undefined;\n }\n\n /**\n * Create a validation response that allows the request.\n *\n * @returns The validation response.\n */\n Approve(): ValidateResponse {\n return {\n allowed: true,\n };\n }\n\n /**\n * Create a validation response that denies the request.\n *\n * @param statusMessage Optional status message to return to the user.\n * @param statusCode Optional status code to return to the user.\n * @returns The validation response.\n */\n Deny(statusMessage?: string, statusCode?: number): ValidateResponse {\n return {\n allowed: false,\n statusCode,\n statusMessage,\n };\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { Capability } from \"./capability\";\nimport { shouldSkipRequest } from \"./filter\";\nimport { Request, ValidateResponse } from \"./k8s/types\";\nimport { Secret } from \"./k8s/upstream\";\nimport Log from \"./logger\";\nimport { convertFromBase64Map } from \"./utils\";\nimport { PeprValidateRequest } from \"./validate-request\";\n\nexport async function validateProcessor(\n capabilities: Capability[],\n req: Request,\n reqMetadata: Record<string, string>,\n): Promise<ValidateResponse> {\n const wrapped = new PeprValidateRequest(req);\n const response: ValidateResponse = {\n uid: req.uid,\n allowed: true, // Assume it's allowed until a validation check fails\n };\n\n // If the resource is a secret, decode the data\n const isSecret = req.kind.version == \"v1\" && req.kind.kind == \"Secret\";\n if (isSecret) {\n convertFromBase64Map(wrapped.Raw as unknown as Secret);\n }\n\n Log.info(reqMetadata, `Processing validation request`);\n\n for (const { name, bindings, namespaces } of capabilities) {\n const actionMetadata = { ...reqMetadata, name };\n\n for (const action of bindings) {\n // Skip this action if it's not a validation action\n if (!action.validateCallback) {\n continue;\n }\n\n // Continue to the next action without doing anything if this one should be skipped\n if (shouldSkipRequest(action, req, namespaces)) {\n continue;\n }\n\n const label = action.validateCallback.name;\n Log.info(actionMetadata, `Processing matched action ${label}`);\n\n try {\n // Run the validation callback, if it fails set allowed to false\n const resp = await action.validateCallback(wrapped);\n response.allowed = resp.allowed;\n\n // If the validation callback returned a status code or message, set it in the Response\n if (resp.statusCode || resp.statusMessage) {\n response.status = {\n code: resp.statusCode || 400,\n message: resp.statusMessage || `Validation failed for ${name}`,\n };\n }\n\n Log.info(actionMetadata, `Validation Action completed: ${resp.allowed ? \"allowed\" : \"denied\"}`);\n } catch (e) {\n // If any validation throws an error, note the failure in the Response\n Log.error(actionMetadata, `Action failed: ${e}`);\n response.allowed = false;\n response.status = {\n code: 500,\n message: `Action failed with error: ${e}`,\n };\n return response;\n }\n }\n }\n\n return response;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["
|
|
3
|
+
"sources": ["../src/lib.ts", "../src/lib/capability.ts", "../src/lib/logger.ts", "../src/lib/module.ts", "../src/lib/controller/index.ts", "../src/lib/metrics.ts", "../src/lib/mutate-processor.ts", "../src/lib/errors.ts", "../src/lib/k8s.ts", "../src/lib/filter.ts", "../src/lib/mutate-request.ts", "../src/lib/utils.ts", "../src/lib/validate-request.ts", "../src/lib/validate-processor.ts", "../src/lib/controller/store.ts", "../src/lib/watch-processor.ts", "../src/lib/storage.ts"],
|
|
4
|
+
"sourcesContent": ["import { K8s, RegisterKind, fetch, kind, kind as a, fetchStatus } from \"kubernetes-fluent-client\";\nimport * as R from \"ramda\";\n\nimport { Capability } from \"./lib/capability\";\nimport Log from \"./lib/logger\";\nimport { PeprModule } from \"./lib/module\";\nimport { PeprMutateRequest } from \"./lib/mutate-request\";\nimport { PeprValidateRequest } from \"./lib/validate-request\";\nimport * as PeprUtils from \"./lib/utils\";\n\n// Import type information for external packages\nimport type * as RTypes from \"ramda\";\n\nexport {\n a,\n kind,\n /** PeprModule is used to setup a complete Pepr Module: `new PeprModule(cfg, {...capabilities})` */\n PeprModule,\n PeprMutateRequest,\n PeprValidateRequest,\n PeprUtils,\n RegisterKind,\n K8s,\n Capability,\n Log,\n R,\n fetch,\n fetchStatus,\n\n // Export the imported type information for external packages\n RTypes,\n};\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { GenericClass, GroupVersionKind, modelToGroupVersionKind } from \"kubernetes-fluent-client\";\nimport { WatchAction } from \"kubernetes-fluent-client/dist/fluent/types\";\nimport { pickBy } from \"ramda\";\n\nimport Log from \"./logger\";\nimport { isBuildMode, isDevMode, isWatchMode } from \"./module\";\nimport { PeprStore, Storage } from \"./storage\";\nimport {\n Binding,\n BindingFilter,\n BindingWithName,\n CapabilityCfg,\n CapabilityExport,\n Event,\n MutateAction,\n MutateActionChain,\n ValidateAction,\n ValidateActionChain,\n WhenSelector,\n} from \"./types\";\n\nconst registerAdmission = isBuildMode() || !isWatchMode();\nconst registerWatch = isBuildMode() || isWatchMode() || isDevMode();\n\n/**\n * A capability is a unit of functionality that can be registered with the Pepr runtime.\n */\nexport class Capability implements CapabilityExport {\n #name: string;\n #description: string;\n #namespaces?: string[] | undefined;\n #bindings: Binding[] = [];\n #store = new Storage();\n #registered = false;\n\n /**\n * Store is a key-value data store that can be used to persist data that should be shared\n * between requests. Each capability has its own store, and the data is persisted in Kubernetes\n * in the `pepr-system` namespace.\n *\n * Note: You should only access the store from within an action.\n */\n Store: PeprStore = {\n clear: this.#store.clear,\n getItem: this.#store.getItem,\n removeItem: this.#store.removeItem,\n setItem: this.#store.setItem,\n subscribe: this.#store.subscribe,\n onReady: this.#store.onReady,\n };\n\n get bindings() {\n return this.#bindings;\n }\n\n get name() {\n return this.#name;\n }\n\n get description() {\n return this.#description;\n }\n\n get namespaces() {\n return this.#namespaces || [];\n }\n\n constructor(cfg: CapabilityCfg) {\n this.#name = cfg.name;\n this.#description = cfg.description;\n this.#namespaces = cfg.namespaces;\n\n Log.info(`Capability ${this.#name} registered`);\n Log.debug(cfg);\n }\n\n /**\n * Register the store with the capability. This is called automatically by the Pepr controller.\n *\n * @param store\n */\n registerStore = () => {\n Log.info(`Registering store for ${this.#name}`);\n\n if (this.#registered) {\n throw new Error(`Store already registered for ${this.#name}`);\n }\n\n this.#registered = true;\n\n // Pass back any ready callback to the controller\n return {\n store: this.#store,\n };\n };\n\n /**\n * The When method is used to register a action to be executed when a Kubernetes resource is\n * processed by Pepr. The action will be executed if the resource matches the specified kind and any\n * filters that are applied.\n *\n * @param model the KubernetesObject model to match\n * @param kind if using a custom KubernetesObject not available in `a.*`, specify the GroupVersionKind\n * @returns\n */\n When = <T extends GenericClass>(model: T, kind?: GroupVersionKind): WhenSelector<T> => {\n const matchedKind = modelToGroupVersionKind(model.name);\n\n // If the kind is not specified and the model is not a KubernetesObject, throw an error\n if (!matchedKind && !kind) {\n throw new Error(`Kind not specified for ${model.name}`);\n }\n\n const binding: Binding = {\n model,\n // If the kind is not specified, use the matched kind from the model\n kind: kind || matchedKind,\n event: Event.Any,\n filters: {\n name: \"\",\n namespaces: [],\n labels: {},\n annotations: {},\n },\n };\n\n const bindings = this.#bindings;\n const prefix = `${this.#name}: ${model.name}`;\n const commonChain = { WithLabel, WithAnnotation, Mutate, Validate, Watch };\n const isNotEmpty = (value: object) => Object.keys(value).length > 0;\n const log = (message: string, cbString: string) => {\n const filteredObj = pickBy(isNotEmpty, binding.filters);\n\n Log.info(`${message} configured for ${binding.event}`, prefix);\n Log.info(filteredObj, prefix);\n Log.debug(cbString, prefix);\n };\n\n function Validate(validateCallback: ValidateAction<T>): ValidateActionChain<T> {\n if (registerAdmission) {\n log(\"Validate Action\", validateCallback.toString());\n\n // Push the binding to the list of bindings for this capability as a new BindingAction\n // with the callback function to preserve\n bindings.push({\n ...binding,\n isValidate: true,\n validateCallback,\n });\n }\n\n return { Watch };\n }\n\n function Mutate(mutateCallback: MutateAction<T>): MutateActionChain<T> {\n if (registerAdmission) {\n log(\"Mutate Action\", mutateCallback.toString());\n\n // Push the binding to the list of bindings for this capability as a new BindingAction\n // with the callback function to preserve\n bindings.push({\n ...binding,\n isMutate: true,\n mutateCallback,\n });\n }\n\n // Now only allow adding actions to the same binding\n return { Watch, Validate };\n }\n\n function Watch(watchCallback: WatchAction<T>) {\n if (registerWatch) {\n log(\"Watch Action\", watchCallback.toString());\n\n bindings.push({\n ...binding,\n isWatch: true,\n watchCallback,\n });\n }\n }\n\n function InNamespace(...namespaces: string[]): BindingWithName<T> {\n Log.debug(`Add namespaces filter ${namespaces}`, prefix);\n binding.filters.namespaces.push(...namespaces);\n return { ...commonChain, WithName };\n }\n\n function WithName(name: string): BindingFilter<T> {\n Log.debug(`Add name filter ${name}`, prefix);\n binding.filters.name = name;\n return commonChain;\n }\n\n function WithLabel(key: string, value = \"\"): BindingFilter<T> {\n Log.debug(`Add label filter ${key}=${value}`, prefix);\n binding.filters.labels[key] = value;\n return commonChain;\n }\n\n function WithAnnotation(key: string, value = \"\"): BindingFilter<T> {\n Log.debug(`Add annotation filter ${key}=${value}`, prefix);\n binding.filters.annotations[key] = value;\n return commonChain;\n }\n\n function bindEvent(event: Event) {\n binding.event = event;\n return {\n ...commonChain,\n InNamespace,\n WithName,\n };\n }\n\n return {\n IsCreatedOrUpdated: () => bindEvent(Event.CreateOrUpdate),\n IsCreated: () => bindEvent(Event.Create),\n IsUpdated: () => bindEvent(Event.Update),\n IsDeleted: () => bindEvent(Event.Delete),\n };\n };\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { pino } from \"pino\";\n\nconst isPrettyLog = process.env.PEPR_PRETTY_LOGS === \"true\";\n\nconst pretty = {\n target: \"pino-pretty\",\n options: {\n colorize: true,\n },\n};\n\nconst transport = isPrettyLog ? pretty : undefined;\n\nconst Log = pino({\n transport,\n});\n\nif (process.env.LOG_LEVEL) {\n Log.level = process.env.LOG_LEVEL;\n}\n\nexport default Log;\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { clone } from \"ramda\";\n\nimport { Capability } from \"./capability\";\nimport { Controller } from \"./controller\";\nimport { ValidateError } from \"./errors\";\nimport { AdmissionRequest, MutateResponse, ValidateResponse, WebhookIgnore } from \"./k8s\";\nimport { CapabilityExport } from \"./types\";\nimport { setupWatch } from \"./watch-processor\";\n\n/** Global configuration for the Pepr runtime. */\nexport type ModuleConfig = {\n /** The user-defined name for the module */\n name: string;\n /** The Pepr version this module uses */\n peprVersion?: string;\n /** The user-defined version of the module */\n appVersion?: string;\n /** A unique identifier for this Pepr module. This is automatically generated by Pepr. */\n uuid: string;\n /** A description of the Pepr module and what it does. */\n description?: string;\n /** Reject K8s resource AdmissionRequests on error. */\n onError?: string;\n /** Configure global exclusions that will never be processed by Pepr. */\n alwaysIgnore: WebhookIgnore;\n /** Define the log level for the in-cluster controllers */\n logLevel?: string;\n};\n\nexport type PackageJSON = {\n description: string;\n pepr: ModuleConfig;\n};\n\nexport type PeprModuleOptions = {\n deferStart?: boolean;\n\n /** A user-defined callback to pre-process or intercept a Pepr request from K8s immediately before it is processed */\n beforeHook?: (req: AdmissionRequest) => void;\n\n /** A user-defined callback to post-process or intercept a Pepr response just before it is returned to K8s */\n afterHook?: (res: MutateResponse | ValidateResponse) => void;\n};\n\n// Track if this is a watch mode controller\nexport const isWatchMode = () => process.env.PEPR_WATCH_MODE === \"true\";\n\n// Track if Pepr is running in build mode\nexport const isBuildMode = () => process.env.PEPR_MODE === \"build\";\n\nexport const isDevMode = () => process.env.PEPR_MODE === \"dev\";\n\nexport class PeprModule {\n #controller!: Controller;\n\n /**\n * Create a new Pepr runtime\n *\n * @param config The configuration for the Pepr runtime\n * @param capabilities The capabilities to be loaded into the Pepr runtime\n * @param opts Options for the Pepr runtime\n */\n constructor({ description, pepr }: PackageJSON, capabilities: Capability[] = [], opts: PeprModuleOptions = {}) {\n const config: ModuleConfig = clone(pepr);\n config.description = description;\n\n // Need to validate at runtime since TS gets sad about parsing the package.json\n ValidateError(config.onError);\n\n // Handle build mode\n if (isBuildMode()) {\n // Fail if process.send is not defined\n if (!process.send) {\n throw new Error(\"process.send is not defined\");\n }\n\n const exportedCapabilities: CapabilityExport[] = [];\n\n // Send capability map to parent process\n for (const capability of capabilities) {\n // Convert the capability to a capability config\n exportedCapabilities.push({\n name: capability.name,\n description: capability.description,\n namespaces: capability.namespaces,\n bindings: capability.bindings,\n });\n }\n\n // Send the capabilities back to the parent process\n process.send(exportedCapabilities);\n\n return;\n }\n\n this.#controller = new Controller(config, capabilities, opts.beforeHook, opts.afterHook, () => {\n // Wait for the controller to be ready before setting up watches\n if (isWatchMode() || isDevMode()) {\n setupWatch(capabilities);\n }\n });\n\n // Stop processing if deferStart is set to true\n if (opts.deferStart) {\n return;\n }\n\n this.start();\n }\n\n /**\n * Start the Pepr runtime manually.\n * Normally this is called automatically when the Pepr module is instantiated, but can be called manually if `deferStart` is set to `true` in the constructor.\n *\n * @param port\n */\n start = (port = 3000) => {\n this.#controller.startServer(port);\n };\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport express, { NextFunction } from \"express\";\nimport fs from \"fs\";\nimport https from \"https\";\n\nimport { Capability } from \"../capability\";\nimport { MutateResponse, AdmissionRequest, ValidateResponse } from \"../k8s\";\nimport Log from \"../logger\";\nimport { MetricsCollector } from \"../metrics\";\nimport { ModuleConfig, isWatchMode } from \"../module\";\nimport { mutateProcessor } from \"../mutate-processor\";\nimport { validateProcessor } from \"../validate-processor\";\nimport { PeprControllerStore } from \"./store\";\n\nexport class Controller {\n // Track whether the server is running\n #running = false;\n\n // Metrics collector\n #metricsCollector = new MetricsCollector(\"pepr\");\n\n // The token used to authenticate requests\n #token = \"\";\n\n // The express app instance\n readonly #app = express();\n\n // Initialized with the constructor\n readonly #config: ModuleConfig;\n readonly #capabilities: Capability[];\n readonly #beforeHook?: (req: AdmissionRequest) => void;\n readonly #afterHook?: (res: MutateResponse) => void;\n\n constructor(\n config: ModuleConfig,\n capabilities: Capability[],\n beforeHook?: (req: AdmissionRequest) => void,\n afterHook?: (res: MutateResponse) => void,\n onReady?: () => void,\n ) {\n this.#config = config;\n this.#capabilities = capabilities;\n\n // Initialize the Pepr store for each capability\n new PeprControllerStore(config, capabilities, () => {\n this.#bindEndpoints();\n onReady && onReady();\n Log.info(\"\u2705 Controller startup complete\");\n });\n\n // Middleware for logging requests\n this.#app.use(Controller.#logger);\n\n // Middleware for parsing JSON, limit to 2mb vs 100K for K8s compatibility\n this.#app.use(express.json({ limit: \"2mb\" }));\n\n if (beforeHook) {\n Log.info(`Using beforeHook: ${beforeHook}`);\n this.#beforeHook = beforeHook;\n }\n\n if (afterHook) {\n Log.info(`Using afterHook: ${afterHook}`);\n this.#afterHook = afterHook;\n }\n }\n\n /** Start the webhook server */\n startServer = (port: number) => {\n if (this.#running) {\n throw new Error(\"Cannot start Pepr module: Pepr module was not instantiated with deferStart=true\");\n }\n\n // Load SSL certificate and key\n const options = {\n key: fs.readFileSync(process.env.SSL_KEY_PATH || \"/etc/certs/tls.key\"),\n cert: fs.readFileSync(process.env.SSL_CERT_PATH || \"/etc/certs/tls.crt\"),\n };\n\n // Get the API token if not in watch mode\n if (!isWatchMode()) {\n // Get the API token from the environment variable or the mounted secret\n this.#token = process.env.PEPR_API_TOKEN || fs.readFileSync(\"/app/api-token/value\").toString().trim();\n Log.info(`Using API token: ${this.#token}`);\n\n if (!this.#token) {\n throw new Error(\"API token not found\");\n }\n }\n\n // Create HTTPS server\n const server = https.createServer(options, this.#app).listen(port);\n\n // Handle server listening event\n server.on(\"listening\", () => {\n Log.info(`Server listening on port ${port}`);\n // Track that the server is running\n this.#running = true;\n });\n\n // Handle EADDRINUSE errors\n server.on(\"error\", (e: { code: string }) => {\n if (e.code === \"EADDRINUSE\") {\n Log.warn(\n `Address in use, retrying in 2 seconds. If this persists, ensure ${port} is not in use, e.g. \"lsof -i :${port}\"`,\n );\n setTimeout(() => {\n server.close();\n server.listen(port);\n }, 2000);\n }\n });\n\n // Listen for the SIGTERM signal and gracefully close the server\n process.on(\"SIGTERM\", () => {\n Log.info(\"Received SIGTERM, closing server\");\n server.close(() => {\n Log.info(\"Server closed\");\n process.exit(0);\n });\n });\n };\n\n #bindEndpoints = () => {\n // Health check endpoint\n this.#app.get(\"/healthz\", Controller.#healthz);\n\n // Metrics endpoint\n this.#app.get(\"/metrics\", this.#metrics);\n\n if (isWatchMode()) {\n return;\n }\n\n // Require auth for webhook endpoints\n this.#app.use([\"/mutate/:token\", \"/validate/:token\"], this.#validateToken);\n\n // Mutate endpoint\n this.#app.post(\"/mutate/:token\", this.#admissionReq(\"Mutate\"));\n\n // Validate endpoint\n this.#app.post(\"/validate/:token\", this.#admissionReq(\"Validate\"));\n };\n\n /**\n * Validate the token in the request path\n *\n * @param req The incoming request\n * @param res The outgoing response\n * @param next The next middleware function\n * @returns\n */\n #validateToken = (req: express.Request, res: express.Response, next: NextFunction) => {\n // Validate the token\n const { token } = req.params;\n if (token !== this.#token) {\n const err = `Unauthorized: invalid token '${token.replace(/[^\\w]/g, \"_\")}'`;\n Log.warn(err);\n res.status(401).send(err);\n this.#metricsCollector.alert();\n return;\n }\n\n // Token is valid, continue\n next();\n };\n\n /**\n * Metrics endpoint handler\n *\n * @param req the incoming request\n * @param res the outgoing response\n */\n #metrics = async (req: express.Request, res: express.Response) => {\n try {\n res.send(await this.#metricsCollector.getMetrics());\n } catch (err) {\n Log.error(err);\n res.status(500).send(\"Internal Server Error\");\n }\n };\n\n /**\n * Admission request handler for both mutate and validate requests\n *\n * @param admissionKind the type of admission request\n * @returns the request handler\n */\n #admissionReq = (admissionKind: \"Mutate\" | \"Validate\") => {\n // Create the admission request handler\n return async (req: express.Request, res: express.Response) => {\n // Start the metrics timer\n const startTime = MetricsCollector.observeStart();\n\n try {\n // Get the request from the body or create an empty request\n const request: AdmissionRequest = req.body?.request || ({} as AdmissionRequest);\n\n // Run the before hook if it exists\n this.#beforeHook && this.#beforeHook(request || {});\n\n // Setup identifiers for logging\n const name = request?.name ? `/${request.name}` : \"\";\n const namespace = request?.namespace || \"\";\n const gvk = request?.kind || { group: \"\", version: \"\", kind: \"\" };\n\n const reqMetadata = {\n uid: request.uid,\n namespace,\n name,\n };\n\n Log.info({ ...reqMetadata, gvk, operation: request.operation, admissionKind }, \"Incoming request\");\n Log.debug({ ...reqMetadata, request }, \"Incoming request body\");\n\n // Process the request\n let response: MutateResponse | ValidateResponse;\n\n // Call mutate or validate based on the admission kind\n if (admissionKind === \"Mutate\") {\n response = await mutateProcessor(this.#config, this.#capabilities, request, reqMetadata);\n } else {\n response = await validateProcessor(this.#capabilities, request, reqMetadata);\n }\n\n // Run the after hook if it exists\n this.#afterHook && this.#afterHook(response);\n\n // Log the response\n Log.debug({ ...reqMetadata, response }, \"Outgoing response\");\n\n // Send a no prob bob response\n res.send({\n apiVersion: \"admission.k8s.io/v1\",\n kind: \"AdmissionReview\",\n response,\n });\n this.#metricsCollector.observeEnd(startTime, admissionKind);\n } catch (err) {\n Log.error(err);\n res.status(500).send(\"Internal Server Error\");\n this.#metricsCollector.error();\n }\n };\n };\n\n /**\n * Middleware for logging requests\n *\n * @param req the incoming request\n * @param res the outgoing response\n * @param next the next middleware function\n */\n static #logger(req: express.Request, res: express.Response, next: express.NextFunction) {\n const startTime = Date.now();\n\n res.on(\"finish\", () => {\n const elapsedTime = Date.now() - startTime;\n const message = {\n uid: req.body?.request?.uid,\n method: req.method,\n url: req.originalUrl,\n status: res.statusCode,\n duration: `${elapsedTime} ms`,\n };\n\n res.statusCode >= 300 ? Log.warn(message) : Log.info(message);\n });\n\n next();\n }\n /**\n * Health check endpoint handler\n *\n * @param req the incoming request\n * @param res the outgoing response\n */\n static #healthz(req: express.Request, res: express.Response) {\n try {\n res.send(\"OK\");\n } catch (err) {\n Log.error(err);\n res.status(500).send(\"Internal Server Error\");\n }\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\n/* eslint-disable class-methods-use-this */\n\nimport { performance } from \"perf_hooks\";\nimport promClient, { Counter, Registry, Summary } from \"prom-client\";\nimport Log from \"./logger\";\n\nconst loggingPrefix = \"MetricsCollector\";\n\ninterface MetricNames {\n errors: string;\n alerts: string;\n mutate: string;\n validate: string;\n}\n\ninterface MetricArgs {\n name: string;\n help: string;\n registers: Registry[];\n}\n\n/**\n * MetricsCollector class handles metrics collection using prom-client and performance hooks.\n */\nexport class MetricsCollector {\n #registry: Registry;\n #counters: Map<string, Counter<string>> = new Map();\n #summaries: Map<string, Summary<string>> = new Map();\n #prefix: string;\n\n #metricNames: MetricNames = {\n errors: \"errors\",\n alerts: \"alerts\",\n mutate: \"Mutate\",\n validate: \"Validate\",\n };\n\n /**\n * Creates a MetricsCollector instance with prefixed metrics.\n * @param [prefix='pepr'] - The prefix for the metric names.\n */\n constructor(prefix = \"pepr\") {\n this.#registry = new Registry();\n this.#prefix = prefix;\n this.addCounter(this.#metricNames.errors, \"Mutation/Validate errors encountered\");\n this.addCounter(this.#metricNames.alerts, \"Mutation/Validate bad api token received\");\n this.addSummary(this.#metricNames.mutate, \"Mutation operation summary\");\n this.addSummary(this.#metricNames.validate, \"Validation operation summary\");\n }\n\n #getMetricName = (name: string) => `${this.#prefix}_${name}`;\n\n #addMetric = <T extends Counter<string> | Summary<string>>(\n collection: Map<string, T>,\n MetricType: new (args: MetricArgs) => T,\n name: string,\n help: string,\n ) => {\n if (collection.has(this.#getMetricName(name))) {\n Log.debug(`Metric for ${name} already exists`, loggingPrefix);\n return;\n }\n\n const metric = new MetricType({\n name: this.#getMetricName(name),\n help,\n registers: [this.#registry],\n });\n\n collection.set(this.#getMetricName(name), metric);\n };\n\n addCounter = (name: string, help: string) => {\n this.#addMetric(this.#counters, promClient.Counter, name, help);\n };\n\n addSummary = (name: string, help: string) => {\n this.#addMetric(this.#summaries, promClient.Summary, name, help);\n };\n\n incCounter = (name: string) => {\n this.#counters.get(this.#getMetricName(name))?.inc();\n };\n\n /**\n * Increments the error counter.\n */\n error = () => this.incCounter(this.#metricNames.errors);\n\n /**\n * Increments the alerts counter.\n */\n alert = () => this.incCounter(this.#metricNames.alerts);\n\n /**\n * Observes the duration since the provided start time and updates the summary.\n * @param startTime - The start time.\n * @param name - The metrics summary to increment.\n */\n observeEnd = (startTime: number, name: string = this.#metricNames.mutate) => {\n this.#summaries.get(this.#getMetricName(name))?.observe(performance.now() - startTime);\n };\n\n /**\n * Fetches the current metrics from the registry.\n * @returns The metrics.\n */\n getMetrics = () => this.#registry.metrics();\n\n /**\n * Returns the current timestamp from performance.now() method. Useful for start timing an operation.\n * @returns The timestamp.\n */\n static observeStart() {\n return performance.now();\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport jsonPatch from \"fast-json-patch\";\nimport { kind } from \"kubernetes-fluent-client\";\n\nimport { Capability } from \"./capability\";\nimport { Errors } from \"./errors\";\nimport { shouldSkipRequest } from \"./filter\";\nimport { MutateResponse, AdmissionRequest } from \"./k8s\";\nimport Log from \"./logger\";\nimport { ModuleConfig } from \"./module\";\nimport { PeprMutateRequest } from \"./mutate-request\";\nimport { base64Encode, convertFromBase64Map, convertToBase64Map } from \"./utils\";\n\nexport async function mutateProcessor(\n config: ModuleConfig,\n capabilities: Capability[],\n req: AdmissionRequest,\n reqMetadata: Record<string, string>,\n): Promise<MutateResponse> {\n const wrapped = new PeprMutateRequest(req);\n const response: MutateResponse = {\n uid: req.uid,\n warnings: [],\n allowed: false,\n };\n\n // Track whether any capability matched the request\n let matchedAction = false;\n\n // Track data fields that should be skipped during decoding\n let skipDecode: string[] = [];\n\n // If the resource is a secret, decode the data\n const isSecret = req.kind.version == \"v1\" && req.kind.kind == \"Secret\";\n if (isSecret) {\n skipDecode = convertFromBase64Map(wrapped.Raw as unknown as kind.Secret);\n }\n\n Log.info(reqMetadata, `Processing request`);\n\n for (const { name, bindings, namespaces } of capabilities) {\n const actionMetadata = { ...reqMetadata, name };\n\n for (const action of bindings) {\n // Skip this action if it's not a mutate action\n if (!action.mutateCallback) {\n continue;\n }\n\n // Continue to the next action without doing anything if this one should be skipped\n if (shouldSkipRequest(action, req, namespaces)) {\n continue;\n }\n\n const label = action.mutateCallback.name;\n Log.info(actionMetadata, `Processing matched action ${label}`);\n\n matchedAction = true;\n\n // Add annotations to the request to indicate that the capability started processing\n // this will allow tracking of failed mutations that were permitted to continue\n const updateStatus = (status: string) => {\n // Only update the status if the request is a CREATE or UPDATE (we don't use CONNECT)\n if (req.operation == \"DELETE\") {\n return;\n }\n\n const identifier = `${config.uuid}.pepr.dev/${name}`;\n wrapped.Raw.metadata = wrapped.Raw.metadata || {};\n wrapped.Raw.metadata.annotations = wrapped.Raw.metadata.annotations || {};\n wrapped.Raw.metadata.annotations[identifier] = status;\n };\n\n updateStatus(\"started\");\n\n try {\n // Run the action\n await action.mutateCallback(wrapped);\n\n Log.info(actionMetadata, `Action succeeded`);\n\n // Add annotations to the request to indicate that the capability succeeded\n updateStatus(\"succeeded\");\n } catch (e) {\n Log.warn(actionMetadata, `Action failed: ${e}`);\n updateStatus(\"warning\");\n\n // Annoying ts false positive\n response.warnings = response.warnings || [];\n response.warnings.push(`Action failed: ${e}`);\n\n switch (config.onError) {\n case Errors.reject:\n Log.error(actionMetadata, `Action failed: ${e}`);\n response.result = \"Pepr module configured to reject on error\";\n return response;\n\n case Errors.audit:\n response.auditAnnotations = response.auditAnnotations || {};\n response.auditAnnotations[Date.now()] = e;\n break;\n }\n }\n }\n }\n\n // If we've made it this far, the request is allowed\n response.allowed = true;\n\n // If no capability matched the request, exit early\n if (!matchedAction) {\n Log.info(reqMetadata, `No matching actions found`);\n return response;\n }\n\n // delete operations can't be mutate, just return before the transformation\n if (req.operation == \"DELETE\") {\n return response;\n }\n\n const transformed = wrapped.Raw;\n\n // Post-process the Secret requests to convert it back to the original format\n if (isSecret) {\n convertToBase64Map(transformed as unknown as kind.Secret, skipDecode);\n }\n\n // Compare the original request to the modified request to get the patches\n const patches = jsonPatch.compare(req.object, transformed);\n\n // Only add the patch if there are patches to apply\n if (patches.length > 0) {\n response.patchType = \"JSONPatch\";\n // Webhook must be base64-encoded\n // https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#response\n response.patch = base64Encode(JSON.stringify(patches));\n }\n\n // Remove the warnings array if it's empty\n if (response.warnings && response.warnings.length < 1) {\n delete response.warnings;\n }\n\n Log.debug({ ...reqMetadata, patches }, `Patches generated`);\n\n return response;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nexport const Errors = {\n audit: \"audit\",\n ignore: \"ignore\",\n reject: \"reject\",\n};\n\nexport const ErrorList = Object.values(Errors);\n\n/**\n * Validate the error or throw an error\n * @param error\n */\nexport function ValidateError(error = \"\") {\n if (!ErrorList.includes(error)) {\n throw new Error(`Invalid error: ${error}. Must be one of: ${ErrorList.join(\", \")}`);\n }\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { GenericKind, GroupVersionKind, KubernetesObject, RegisterKind } from \"kubernetes-fluent-client\";\n\nexport enum Operation {\n CREATE = \"CREATE\",\n UPDATE = \"UPDATE\",\n DELETE = \"DELETE\",\n CONNECT = \"CONNECT\",\n}\n\n/**\n * PeprStore for internal use by Pepr. This is used to store arbitrary data in the cluster.\n */\nexport class PeprStore extends GenericKind {\n declare data: {\n [key: string]: string;\n };\n}\n\nexport const peprStoreGVK = {\n kind: \"PeprStore\",\n version: \"v1\",\n group: \"pepr.dev\",\n};\n\nRegisterKind(PeprStore, peprStoreGVK);\n\n/**\n * GroupVersionResource unambiguously identifies a resource. It doesn't anonymously include GroupVersion\n * to avoid automatic coercion. It doesn't use a GroupVersion to avoid custom marshalling\n */\nexport interface GroupVersionResource {\n readonly group: string;\n readonly version: string;\n readonly resource: string;\n}\n\n/**\n * A Kubernetes admission request to be processed by a capability.\n */\nexport interface AdmissionRequest<T = KubernetesObject> {\n /** UID is an identifier for the individual request/response. */\n readonly uid: string;\n\n /** Kind is the fully-qualified type of object being submitted (for example, v1.Pod or autoscaling.v1.Scale) */\n readonly kind: GroupVersionKind;\n\n /** Resource is the fully-qualified resource being requested (for example, v1.pods) */\n readonly resource: GroupVersionResource;\n\n /** SubResource is the sub-resource being requested, if any (for example, \"status\" or \"scale\") */\n readonly subResource?: string;\n\n /** RequestKind is the fully-qualified type of the original API request (for example, v1.Pod or autoscaling.v1.Scale). */\n readonly requestKind?: GroupVersionKind;\n\n /** RequestResource is the fully-qualified resource of the original API request (for example, v1.pods). */\n readonly requestResource?: GroupVersionResource;\n\n /** RequestSubResource is the sub-resource of the original API request, if any (for example, \"status\" or \"scale\"). */\n readonly requestSubResource?: string;\n\n /**\n * Name is the name of the object as presented in the request. On a CREATE operation, the client may omit name and\n * rely on the server to generate the name. If that is the case, this method will return the empty string.\n */\n readonly name: string;\n\n /** Namespace is the namespace associated with the request (if any). */\n readonly namespace?: string;\n\n /**\n * Operation is the operation being performed. This may be different than the operation\n * requested. e.g. a patch can result in either a CREATE or UPDATE Operation.\n */\n readonly operation: Operation;\n\n /** UserInfo is information about the requesting user */\n readonly userInfo: {\n /** The name that uniquely identifies this user among all active users. */\n username?: string;\n\n /**\n * A unique value that identifies this user across time. If this user is deleted\n * and another user by the same name is added, they will have different UIDs.\n */\n uid?: string;\n\n /** The names of groups this user is a part of. */\n groups?: string[];\n\n /** Any additional information provided by the authenticator. */\n extra?: {\n [key: string]: string[];\n };\n };\n\n /** Object is the object from the incoming request prior to default values being applied */\n readonly object: T;\n\n /** OldObject is the existing object. Only populated for UPDATE or DELETE requests. */\n readonly oldObject?: T;\n\n /** DryRun indicates that modifications will definitely not be persisted for this request. Defaults to false. */\n readonly dryRun?: boolean;\n\n /**\n * Options contains the options for the operation being performed.\n * e.g. `meta.k8s.io/v1.DeleteOptions` or `meta.k8s.io/v1.CreateOptions`. This may be\n * different than the options the caller provided. e.g. for a patch request the performed\n * Operation might be a CREATE, in which case the Options will a\n * `meta.k8s.io/v1.CreateOptions` even though the caller provided `meta.k8s.io/v1.PatchOptions`.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly options?: any;\n}\n\nexport interface MutateResponse {\n /** UID is an identifier for the individual request/response. This must be copied over from the corresponding AdmissionRequest. */\n uid: string;\n\n /** Allowed indicates whether or not the admission request was permitted. */\n allowed: boolean;\n\n /** Result contains extra details into why an admission request was denied. This field IS NOT consulted in any way if \"Allowed\" is \"true\". */\n result?: string;\n\n /** The patch body. Currently we only support \"JSONPatch\" which implements RFC 6902. */\n patch?: string;\n\n /** The type of Patch. Currently we only allow \"JSONPatch\". */\n patchType?: \"JSONPatch\";\n\n /**\n * AuditAnnotations is an unstructured key value map set by remote admission controller (e.g. error=image-blacklisted).\n *\n * See https://kubernetes.io/docs/reference/labels-annotations-taints/audit-annotations/ for more information\n */\n auditAnnotations?: {\n [key: string]: string;\n };\n\n /** warnings is a list of warning messages to return to the requesting API client. */\n warnings?: string[];\n}\n\nexport interface ValidateResponse extends MutateResponse {\n /** Status contains extra details into why an admission request was denied. This field IS NOT consulted in any way if \"Allowed\" is \"true\". */\n status?: {\n /** A machine-readable description of why this operation is in the\n \"Failure\" status. If this value is empty there is no information available. */\n code: number;\n\n /** A human-readable description of the status of this operation. */\n message: string;\n };\n}\n\nexport type WebhookIgnore = {\n /**\n * List of Kubernetes namespaces to always ignore.\n * Any resources in these namespaces will be ignored by Pepr.\n *\n * Note: `kube-system` and `pepr-system` are always ignored.\n */\n namespaces?: string[];\n /**\n * List of Kubernetes labels to always ignore.\n * Any resources with these labels will be ignored by Pepr.\n *\n * The example below will ignore any resources with the label `my-label=ulta-secret`:\n * ```\n * alwaysIgnore:\n * labels: [{ \"my-label\": \"ultra-secret\" }]\n * ```\n */\n labels?: Record<string, string>[];\n};\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { AdmissionRequest, Operation } from \"./k8s\";\nimport logger from \"./logger\";\nimport { Binding, Event } from \"./types\";\n\n/**\n * shouldSkipRequest determines if a request should be skipped based on the binding filters.\n *\n * @param binding the action binding\n * @param req the incoming request\n * @returns\n */\nexport function shouldSkipRequest(binding: Binding, req: AdmissionRequest, capabilityNamespaces: string[]) {\n const { group, kind, version } = binding.kind || {};\n const { namespaces, labels, annotations, name } = binding.filters || {};\n const operation = req.operation.toUpperCase();\n // Use the old object if the request is a DELETE operation\n const srcObject = operation === Operation.DELETE ? req.oldObject : req.object;\n const { metadata } = srcObject || {};\n const combinedNamespaces = [...namespaces, ...capabilityNamespaces];\n\n // Test for matching operation\n if (!binding.event.includes(operation) && !binding.event.includes(Event.Any)) {\n return true;\n }\n\n // Test name first, since it's the most specific\n if (name && name !== req.name) {\n return true;\n }\n\n // Test for matching kinds\n if (kind !== req.kind.kind) {\n return true;\n }\n\n // Test for matching groups\n if (group && group !== req.kind.group) {\n return true;\n }\n\n // Test for matching versions\n if (version && version !== req.kind.version) {\n return true;\n }\n\n // Test for matching namespaces\n if (combinedNamespaces.length && !combinedNamespaces.includes(req.namespace || \"\")) {\n logger.debug(\"Namespace does not match\");\n return true;\n }\n\n // Test for matching labels\n for (const [key, value] of Object.entries(labels)) {\n const testKey = metadata?.labels?.[key];\n\n // First check if the label exists\n if (!testKey) {\n logger.debug(`Label ${key} does not exist`);\n return true;\n }\n\n // Then check if the value matches, if specified\n if (value && testKey !== value) {\n logger.debug(`${testKey} does not match ${value}`);\n return true;\n }\n }\n\n // Test for matching annotations\n for (const [key, value] of Object.entries(annotations)) {\n const testKey = metadata?.annotations?.[key];\n\n // First check if the annotation exists\n if (!testKey) {\n logger.debug(`Annotation ${key} does not exist`);\n return true;\n }\n\n // Then check if the value matches, if specified\n if (value && testKey !== value) {\n logger.debug(`${testKey} does not match ${value}`);\n return true;\n }\n }\n\n // No failed filters, so we should not skip this request\n return false;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { KubernetesObject } from \"kubernetes-fluent-client\";\nimport { clone, mergeDeepRight } from \"ramda\";\n\nimport { AdmissionRequest, Operation } from \"./k8s\";\nimport { DeepPartial } from \"./types\";\n\n/**\n * The RequestWrapper class provides methods to modify Kubernetes objects in the context\n * of a mutating webhook request.\n */\nexport class PeprMutateRequest<T extends KubernetesObject> {\n Raw: T;\n\n #input: AdmissionRequest<T>;\n\n get PermitSideEffects() {\n return !this.#input.dryRun;\n }\n\n /**\n * Indicates whether the request is a dry run.\n * @returns true if the request is a dry run, false otherwise.\n */\n get IsDryRun() {\n return this.#input.dryRun;\n }\n\n /**\n * Provides access to the old resource in the request if available.\n * @returns The old Kubernetes resource object or null if not available.\n */\n get OldResource() {\n return this.#input.oldObject;\n }\n\n /**\n * Provides access to the request object.\n * @returns The request object containing the Kubernetes resource.\n */\n get Request() {\n return this.#input;\n }\n\n /**\n * Creates a new instance of the action class.\n * @param input - The request object containing the Kubernetes resource to modify.\n */\n constructor(input: AdmissionRequest<T>) {\n this.#input = input;\n\n // If this is a DELETE operation, use the oldObject instead\n if (input.operation.toUpperCase() === Operation.DELETE) {\n this.Raw = clone(input.oldObject as T);\n } else {\n // Otherwise, use the incoming object\n this.Raw = clone(input.object);\n }\n\n if (!this.Raw) {\n throw new Error(\"unable to load the request object into PeprRequest.RawP\");\n }\n }\n\n /**\n * Deep merges the provided object with the current resource.\n *\n * @param obj - The object to merge with the current resource.\n */\n Merge = (obj: DeepPartial<T>) => {\n this.Raw = mergeDeepRight(this.Raw, obj) as unknown as T;\n };\n\n /**\n * Updates a label on the Kubernetes resource.\n * @param key - The key of the label to update.\n * @param value - The value of the label.\n * @returns The current action instance for method chaining.\n */\n SetLabel = (key: string, value: string) => {\n const ref = this.Raw;\n\n ref.metadata = ref.metadata ?? {};\n ref.metadata.labels = ref.metadata.labels ?? {};\n ref.metadata.labels[key] = value;\n\n return this;\n };\n\n /**\n * Updates an annotation on the Kubernetes resource.\n * @param key - The key of the annotation to update.\n * @param value - The value of the annotation.\n * @returns The current action instance for method chaining.\n */\n SetAnnotation = (key: string, value: string) => {\n const ref = this.Raw;\n\n ref.metadata = ref.metadata ?? {};\n ref.metadata.annotations = ref.metadata.annotations ?? {};\n ref.metadata.annotations[key] = value;\n\n return this;\n };\n\n /**\n * Removes a label from the Kubernetes resource.\n * @param key - The key of the label to remove.\n * @returns The current Action instance for method chaining.\n */\n RemoveLabel = (key: string) => {\n if (this.Raw.metadata?.labels?.[key]) {\n delete this.Raw.metadata.labels[key];\n }\n\n return this;\n };\n\n /**\n * Removes an annotation from the Kubernetes resource.\n * @param key - The key of the annotation to remove.\n * @returns The current Action instance for method chaining.\n */\n RemoveAnnotation = (key: string) => {\n if (this.Raw.metadata?.annotations?.[key]) {\n delete this.Raw.metadata.annotations[key];\n }\n\n return this;\n };\n\n /**\n * Check if a label exists on the Kubernetes resource.\n *\n * @param key the label key to check\n * @returns\n */\n HasLabel = (key: string) => {\n return this.Raw.metadata?.labels?.[key] !== undefined;\n };\n\n /**\n * Check if an annotation exists on the Kubernetes resource.\n *\n * @param key the annotation key to check\n * @returns\n */\n HasAnnotation = (key: string) => {\n return this.Raw.metadata?.annotations?.[key] !== undefined;\n };\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport Log from \"./logger\";\n\n/** Test if a string is ascii or not */\nexport const isAscii = /^[\\s\\x20-\\x7E]*$/;\n\n/**\n * Encode all ascii values in a map to base64\n * @param obj The object to encode\n * @param skip A list of keys to skip encoding\n */\nexport function convertToBase64Map(obj: { data?: Record<string, string> }, skip: string[]) {\n obj.data = obj.data ?? {};\n for (const key in obj.data) {\n const value = obj.data[key];\n // Only encode ascii values\n obj.data[key] = skip.includes(key) ? value : base64Encode(value);\n }\n}\n\n/**\n * Decode all ascii values in a map from base64 to utf-8\n * @param obj The object to decode\n * @returns A list of keys that were skipped\n */\nexport function convertFromBase64Map(obj: { data?: Record<string, string> }) {\n const skip: string[] = [];\n\n obj.data = obj.data ?? {};\n for (const key in obj.data) {\n if (obj.data[key] == undefined) {\n obj.data[key] = \"\";\n } else {\n const decoded = base64Decode(obj.data[key]);\n if (isAscii.test(decoded)) {\n // Only decode ascii values\n obj.data[key] = decoded;\n } else {\n skip.push(key);\n }\n }\n }\n Log.debug(`Non-ascii data detected in keys: ${skip}, skipping automatic base64 decoding`);\n return skip;\n}\n\n/** Decode a base64 string */\nexport function base64Decode(data: string) {\n return Buffer.from(data, \"base64\").toString(\"utf-8\");\n}\n\n/** Encode a string to base64 */\nexport function base64Encode(data: string) {\n return Buffer.from(data).toString(\"base64\");\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\n/* eslint-disable class-methods-use-this */\n\nimport { KubernetesObject } from \"kubernetes-fluent-client\";\n\nimport { clone } from \"ramda\";\nimport { Operation, AdmissionRequest } from \"./k8s\";\nimport { ValidateActionResponse } from \"./types\";\n\n/**\n * The RequestWrapper class provides methods to modify Kubernetes objects in the context\n * of a mutating webhook request.\n */\nexport class PeprValidateRequest<T extends KubernetesObject> {\n Raw: T;\n\n #input: AdmissionRequest<T>;\n\n /**\n * Provides access to the old resource in the request if available.\n * @returns The old Kubernetes resource object or null if not available.\n */\n get OldResource() {\n return this.#input.oldObject;\n }\n\n /**\n * Provides access to the request object.\n * @returns The request object containing the Kubernetes resource.\n */\n get Request() {\n return this.#input;\n }\n\n /**\n * Creates a new instance of the Action class.\n * @param input - The request object containing the Kubernetes resource to modify.\n */\n constructor(input: AdmissionRequest<T>) {\n this.#input = input;\n\n // If this is a DELETE operation, use the oldObject instead\n if (input.operation.toUpperCase() === Operation.DELETE) {\n this.Raw = clone(input.oldObject as T);\n } else {\n // Otherwise, use the incoming object\n this.Raw = clone(input.object);\n }\n\n if (!this.Raw) {\n throw new Error(\"unable to load the request object into PeprRequest.Raw\");\n }\n }\n\n /**\n * Check if a label exists on the Kubernetes resource.\n *\n * @param key the label key to check\n * @returns\n */\n HasLabel = (key: string) => {\n return this.Raw.metadata?.labels?.[key] !== undefined;\n };\n\n /**\n * Check if an annotation exists on the Kubernetes resource.\n *\n * @param key the annotation key to check\n * @returns\n */\n HasAnnotation = (key: string) => {\n return this.Raw.metadata?.annotations?.[key] !== undefined;\n };\n\n /**\n * Create a validation response that allows the request.\n *\n * @returns The validation response.\n */\n Approve = (): ValidateActionResponse => {\n return {\n allowed: true,\n };\n };\n\n /**\n * Create a validation response that denies the request.\n *\n * @param statusMessage Optional status message to return to the user.\n * @param statusCode Optional status code to return to the user.\n * @returns The validation response.\n */\n Deny = (statusMessage?: string, statusCode?: number): ValidateActionResponse => {\n return {\n allowed: false,\n statusCode,\n statusMessage,\n };\n };\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { kind } from \"kubernetes-fluent-client\";\n\nimport { Capability } from \"./capability\";\nimport { shouldSkipRequest } from \"./filter\";\nimport { AdmissionRequest, ValidateResponse } from \"./k8s\";\nimport Log from \"./logger\";\nimport { convertFromBase64Map } from \"./utils\";\nimport { PeprValidateRequest } from \"./validate-request\";\n\nexport async function validateProcessor(\n capabilities: Capability[],\n req: AdmissionRequest,\n reqMetadata: Record<string, string>,\n): Promise<ValidateResponse> {\n const wrapped = new PeprValidateRequest(req);\n const response: ValidateResponse = {\n uid: req.uid,\n allowed: true, // Assume it's allowed until a validation check fails\n };\n\n // If the resource is a secret, decode the data\n const isSecret = req.kind.version == \"v1\" && req.kind.kind == \"Secret\";\n if (isSecret) {\n convertFromBase64Map(wrapped.Raw as unknown as kind.Secret);\n }\n\n Log.info(reqMetadata, `Processing validation request`);\n\n for (const { name, bindings, namespaces } of capabilities) {\n const actionMetadata = { ...reqMetadata, name };\n\n for (const action of bindings) {\n // Skip this action if it's not a validation action\n if (!action.validateCallback) {\n continue;\n }\n\n // Continue to the next action without doing anything if this one should be skipped\n if (shouldSkipRequest(action, req, namespaces)) {\n continue;\n }\n\n const label = action.validateCallback.name;\n Log.info(actionMetadata, `Processing matched action ${label}`);\n\n try {\n // Run the validation callback, if it fails set allowed to false\n const resp = await action.validateCallback(wrapped);\n response.allowed = resp.allowed;\n\n // If the validation callback returned a status code or message, set it in the Response\n if (resp.statusCode || resp.statusMessage) {\n response.status = {\n code: resp.statusCode || 400,\n message: resp.statusMessage || `Validation failed for ${name}`,\n };\n }\n\n Log.info(actionMetadata, `Validation Action completed: ${resp.allowed ? \"allowed\" : \"denied\"}`);\n } catch (e) {\n // If any validation throws an error, note the failure in the Response\n Log.error(actionMetadata, `Action failed: ${e}`);\n response.allowed = false;\n response.status = {\n code: 500,\n message: `Action failed with error: ${e}`,\n };\n return response;\n }\n }\n }\n\n return response;\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { Operation } from \"fast-json-patch\";\nimport { K8s } from \"kubernetes-fluent-client\";\nimport { startsWith } from \"ramda\";\n\nimport { Capability } from \"../capability\";\nimport { PeprStore } from \"../k8s\";\nimport Log from \"../logger\";\nimport { ModuleConfig } from \"../module\";\nimport { DataOp, DataSender, DataStore, Storage } from \"../storage\";\n\nconst namespace = \"pepr-system\";\nconst debounceBackoff = 5000;\n\nexport class PeprControllerStore {\n #name: string;\n #stores: Record<string, Storage> = {};\n #sendDebounce: NodeJS.Timeout | undefined;\n #onReady?: () => void;\n\n constructor(config: ModuleConfig, capabilities: Capability[], onReady?: () => void) {\n this.#onReady = onReady;\n\n // Setup Pepr State bindings\n this.#name = `pepr-${config.uuid}-store`;\n\n // Establish the store for each capability\n for (const { name, registerStore } of capabilities) {\n // Register the store with the capability\n const { store } = registerStore();\n\n // Bind the store sender to the capability\n store.registerSender(this.#send(name));\n\n // Store the storage instance\n this.#stores[name] = store;\n }\n\n // Add a jitter to the Store creation to avoid collisions\n setTimeout(\n () =>\n K8s(PeprStore)\n .InNamespace(namespace)\n .Get(this.#name)\n // If the get succeeds, setup the watch\n .then(this.#setupWatch)\n // Otherwise, create the resource\n .catch(this.#createStoreResource),\n Math.random() * 3000,\n );\n }\n\n #setupWatch = () => {\n void K8s(PeprStore, { name: this.#name, namespace }).Watch(this.#receive);\n };\n\n #receive = (store: PeprStore) => {\n Log.debug(store, \"Pepr Store update\");\n\n // Wrap the update in a debounced function\n const debounced = () => {\n // Base64 decode the data\n const data: DataStore = store.data || {};\n\n // Loop over each stored capability\n for (const name of Object.keys(this.#stores)) {\n // Get the prefix offset for the keys\n const offset = `${name}-`.length;\n\n // Get any keys that match the capability name prefix\n const filtered: DataStore = {};\n\n // Loop over each key in the secret\n for (const key of Object.keys(data)) {\n // Match on the capability name as a prefix\n if (startsWith(name, key)) {\n // Strip the prefix and store the value\n filtered[key.slice(offset)] = data[key];\n }\n }\n\n // Send the data to the receiver callback\n this.#stores[name].receive(filtered);\n }\n\n // Call the onReady callback if this is the first time the secret has been read\n if (this.#onReady) {\n this.#onReady();\n this.#onReady = undefined;\n }\n };\n\n // Debounce the update to 1 second to avoid multiple rapid calls\n clearTimeout(this.#sendDebounce);\n this.#sendDebounce = setTimeout(debounced, debounceBackoff);\n };\n\n #send = (capabilityName: string) => {\n const sendCache: Record<string, Operation> = {};\n\n // Load the sendCache with patch operations\n const fillCache = (op: DataOp, key: string[], val?: string) => {\n if (op === \"add\") {\n const path = `/data/${capabilityName}-${key}`;\n const value = val || \"\";\n const cacheIdx = [op, path, value].join(\":\");\n\n // Add the operation to the cache\n sendCache[cacheIdx] = { op, path, value };\n\n return;\n }\n\n if (op === \"remove\") {\n if (key.length < 1) {\n throw new Error(`Key is required for REMOVE operation`);\n }\n\n for (const k of key) {\n const path = `/data/${capabilityName}-${k}`;\n const cacheIdx = [op, path].join(\":\");\n\n // Add the operation to the cache\n sendCache[cacheIdx] = { op, path };\n }\n\n return;\n }\n\n // If we get here, the operation is not supported\n throw new Error(`Unsupported operation: ${op}`);\n };\n\n // Send the cached updates to the cluster\n const flushCache = async () => {\n const indexes = Object.keys(sendCache);\n const payload = Object.values(sendCache);\n\n // Loop over each key in the cache and delete it to avoid collisions with other sender calls\n for (const idx of indexes) {\n delete sendCache[idx];\n }\n\n try {\n // Send the patch to the cluster\n await K8s(PeprStore, { namespace, name: this.#name }).Patch(payload);\n } catch (err) {\n Log.error(err, \"Pepr store update failure\");\n\n // On failure to update, re-add the operations to the cache to be retried\n for (const idx of indexes) {\n sendCache[idx] = payload[Number(idx)];\n }\n }\n };\n\n // Create a sender function for the capability to add/remove data from the store\n const sender: DataSender = async (op: DataOp, key: string[], val?: string) => {\n fillCache(op, key, val);\n };\n\n // Send any cached updates every debounceBackoff milliseconds\n setInterval(() => {\n if (Object.keys(sendCache).length > 0) {\n Log.debug(sendCache, \"Sending updates to Pepr store\");\n void flushCache();\n }\n }, debounceBackoff);\n\n return sender;\n };\n\n #createStoreResource = async (e: unknown) => {\n Log.info(`Pepr store not found, creating...`);\n Log.debug(e);\n\n try {\n await K8s(PeprStore).Apply({\n metadata: {\n name: this.#name,\n namespace,\n },\n data: {\n // JSON Patch will die if the data is empty, so we need to add a placeholder\n __pepr_do_not_delete__: \"k-thx-bye\",\n },\n });\n\n // Now that the resource exists, setup the watch\n this.#setupWatch();\n } catch (err) {\n Log.error(err, \"Failed to create Pepr store\");\n }\n };\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { K8s } from \"kubernetes-fluent-client\";\nimport { WatchPhase } from \"kubernetes-fluent-client/dist/fluent/types\";\n\nimport { WatchCfg } from \"kubernetes-fluent-client/dist/fluent/watch\";\nimport { Capability } from \"./capability\";\nimport Log from \"./logger\";\nimport { Binding, Event } from \"./types\";\n\nexport function setupWatch(capabilities: Capability[]) {\n capabilities\n .flatMap(c => c.bindings)\n .filter(binding => binding.isWatch)\n .forEach(runBinding);\n}\n\nasync function runBinding(binding: Binding) {\n // Map the event to the watch phase\n const eventToPhaseMap = {\n [Event.Create]: [WatchPhase.Added],\n [Event.Update]: [WatchPhase.Modified],\n [Event.CreateOrUpdate]: [WatchPhase.Added, WatchPhase.Modified],\n [Event.Delete]: [WatchPhase.Deleted],\n [Event.Any]: [WatchPhase.Added, WatchPhase.Modified, WatchPhase.Deleted],\n };\n\n // Get the phases to match, default to any\n const phaseMatch: WatchPhase[] = eventToPhaseMap[binding.event] || eventToPhaseMap[Event.Any];\n\n const watchCfg: WatchCfg = {\n retryMax: 3,\n retryDelaySec: 5,\n retryFail(e) {\n // If failure continues, log and exit\n Log.error(e, \"Watch failed after 3 attempts, giving up\");\n process.exit(1);\n },\n };\n\n // Watch the resource\n await K8s(binding.model, binding.filters).Watch((obj, type) => {\n // If the type matches the phase, call the watch callback\n if (phaseMatch.includes(type)) {\n try {\n // This may be a promise, but we don't need to wait for it\n void binding.watchCallback?.(obj, type);\n } catch (e) {\n // Errors in the watch callback should not crash the controller\n Log.error(e, \"Error executing watch callback\");\n }\n }\n }, watchCfg);\n}\n", "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2023-Present The Pepr Authors\n\nimport { clone } from \"ramda\";\nimport Log from \"./logger\";\n\nexport type DataOp = \"add\" | \"remove\";\nexport type DataStore = Record<string, string>;\nexport type DataSender = (op: DataOp, keys: string[], value?: string) => void;\nexport type DataReceiver = (data: DataStore) => void;\nexport type Unsubscribe = () => void;\n\nexport interface PeprStore {\n /**\n * Returns the current value associated with the given key, or null if the given key does not exist.\n */\n getItem(key: string): string | null;\n /**\n * Removes all key/value pairs, if there are any.\n */\n clear(): void;\n /**\n * Removes the key/value pair with the given key, if a key/value pair with the given key exists.\n */\n removeItem(key: string): void;\n /**\n * Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.\n */\n setItem(key: string, value: string): void;\n\n /**\n * Subscribe to changes in the store. This API behaves similarly to the [Svelte Store API](https://vercel.com/docs/beginner-sveltekit/svelte-stores#using-the-store).\n *\n * @param listener - The callback to be invoked when the store changes.\n * @returns A function to unsubscribe from the listener.\n */\n subscribe(listener: DataReceiver): Unsubscribe;\n\n /**\n * Register a function to be called when the store is ready.\n */\n onReady(callback: DataReceiver): void;\n}\n\n/**\n * A key-value data store that can be used to persist data that should be shared across Pepr controllers and capabilities.\n *\n * The API is similar to the [Storage API](https://developer.mozilla.org/docs/Web/API/Storage)\n */\nexport class Storage implements PeprStore {\n #store: DataStore = {};\n #send!: DataSender;\n #subscribers: Record<number, DataReceiver> = {};\n #subscriberId = 0;\n #readyHandlers: DataReceiver[] = [];\n\n registerSender = (send: DataSender) => {\n this.#send = send;\n };\n\n receive = (data: DataStore) => {\n Log.debug(data, `Pepr store data received`);\n this.#store = data || {};\n\n this.#onReady();\n\n // Notify all subscribers\n for (const idx in this.#subscribers) {\n // Send a unique clone of the store to each subscriber\n this.#subscribers[idx](clone(this.#store));\n }\n };\n\n getItem = (key: string) => {\n // Return null if the value is the empty string\n return this.#store[key] || null;\n };\n\n clear = () => {\n this.#dispatchUpdate(\"remove\", Object.keys(this.#store));\n };\n\n removeItem = (key: string) => {\n this.#dispatchUpdate(\"remove\", [key]);\n };\n\n setItem = (key: string, value: string) => {\n this.#dispatchUpdate(\"add\", [key], value);\n };\n\n subscribe = (subscriber: DataReceiver) => {\n const idx = this.#subscriberId++;\n this.#subscribers[idx] = subscriber;\n return () => this.unsubscribe(idx);\n };\n\n onReady = (callback: DataReceiver) => {\n this.#readyHandlers.push(callback);\n };\n\n /**\n * Remove a subscriber from the list of subscribers.\n * @param idx - The index of the subscriber to remove.\n */\n unsubscribe = (idx: number) => {\n delete this.#subscribers[idx];\n };\n\n #onReady = () => {\n // Notify all ready handlers with a clone of the store\n for (const handler of this.#readyHandlers) {\n handler(clone(this.#store));\n }\n\n // Make this a noop so that it can't be called again\n this.#onReady = () => {};\n };\n\n /**\n * Dispatch an update to the store and notify all subscribers.\n * @param op - The type of operation to perform.\n * @param keys - The keys to update.\n * @param [value] - The new value.\n */\n #dispatchUpdate = (op: DataOp, keys: string[], value?: string) => {\n this.#send(op, keys, value);\n };\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4CAAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAC,mCAAuE;AACvE,QAAmB;;;ACEnB,IAAAC,mCAAwE;AAExE,IAAAC,gBAAuB;;;ACFvB,kBAAqB;AAErB,IAAM,cAAc,QAAQ,IAAI,qBAAqB;AAErD,IAAM,SAAS;AAAA,EACb,QAAQ;AAAA,EACR,SAAS;AAAA,IACP,UAAU;AAAA,EACZ;AACF;AAEA,IAAM,YAAY,cAAc,SAAS;AAEzC,IAAM,UAAM,kBAAK;AAAA,EACf;AACF,CAAC;AAED,IAAI,QAAQ,IAAI,WAAW;AACzB,MAAI,QAAQ,QAAQ,IAAI;AAC1B;AAEA,IAAO,iBAAQ;;;ACrBf,IAAAC,gBAAsB;;;ACAtB,qBAAsC;AACtC,gBAAe;AACf,mBAAkB;;;ACAlB,wBAA4B;AAC5B,yBAAuD;AAGvD,IAAM,gBAAgB;AAkBf,IAAM,mBAAN,MAAuB;AAAA,EAC5B;AAAA,EACA,YAA0C,oBAAI,IAAI;AAAA,EAClD,aAA2C,oBAAI,IAAI;AAAA,EACnD;AAAA,EAEA,eAA4B;AAAA,IAC1B,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,SAAS,QAAQ;AAC3B,SAAK,YAAY,IAAI,4BAAS;AAC9B,SAAK,UAAU;AACf,SAAK,WAAW,KAAK,aAAa,QAAQ,sCAAsC;AAChF,SAAK,WAAW,KAAK,aAAa,QAAQ,0CAA0C;AACpF,SAAK,WAAW,KAAK,aAAa,QAAQ,4BAA4B;AACtE,SAAK,WAAW,KAAK,aAAa,UAAU,8BAA8B;AAAA,EAC5E;AAAA,EAEA,iBAAiB,CAAC,SAAiB,GAAG,KAAK,OAAO,IAAI,IAAI;AAAA,EAE1D,aAAa,CACX,YACA,YACA,MACA,SACG;AACH,QAAI,WAAW,IAAI,KAAK,eAAe,IAAI,CAAC,GAAG;AAC7C,qBAAI,MAAM,cAAc,IAAI,mBAAmB,aAAa;AAC5D;AAAA,IACF;AAEA,UAAM,SAAS,IAAI,WAAW;AAAA,MAC5B,MAAM,KAAK,eAAe,IAAI;AAAA,MAC9B;AAAA,MACA,WAAW,CAAC,KAAK,SAAS;AAAA,IAC5B,CAAC;AAED,eAAW,IAAI,KAAK,eAAe,IAAI,GAAG,MAAM;AAAA,EAClD;AAAA,EAEA,aAAa,CAAC,MAAc,SAAiB;AAC3C,SAAK,WAAW,KAAK,WAAW,mBAAAC,QAAW,SAAS,MAAM,IAAI;AAAA,EAChE;AAAA,EAEA,aAAa,CAAC,MAAc,SAAiB;AAC3C,SAAK,WAAW,KAAK,YAAY,mBAAAA,QAAW,SAAS,MAAM,IAAI;AAAA,EACjE;AAAA,EAEA,aAAa,CAAC,SAAiB;AAC7B,SAAK,UAAU,IAAI,KAAK,eAAe,IAAI,CAAC,GAAG,IAAI;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,MAAM,KAAK,WAAW,KAAK,aAAa,MAAM;AAAA;AAAA;AAAA;AAAA,EAKtD,QAAQ,MAAM,KAAK,WAAW,KAAK,aAAa,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOtD,aAAa,CAAC,WAAmB,OAAe,KAAK,aAAa,WAAW;AAC3E,SAAK,WAAW,IAAI,KAAK,eAAe,IAAI,CAAC,GAAG,QAAQ,8BAAY,IAAI,IAAI,SAAS;AAAA,EACvF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,MAAM,KAAK,UAAU,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1C,OAAO,eAAe;AACpB,WAAO,8BAAY,IAAI;AAAA,EACzB;AACF;;;ACpHA,6BAAsB;;;ACAf,IAAM,SAAS;AAAA,EACpB,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AACV;AAEO,IAAM,YAAY,OAAO,OAAO,MAAM;AAMtC,SAAS,cAAc,QAAQ,IAAI;AACxC,MAAI,CAAC,UAAU,SAAS,KAAK,GAAG;AAC9B,UAAM,IAAI,MAAM,kBAAkB,KAAK,qBAAqB,UAAU,KAAK,IAAI,CAAC,EAAE;AAAA,EACpF;AACF;;;AChBA,sCAA8E;AAYvE,IAAM,YAAN,cAAwB,4CAAY;AAI3C;AAEO,IAAM,eAAe;AAAA,EAC1B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AACT;AAAA,IAEA,8CAAa,WAAW,YAAY;;;ACb7B,SAAS,kBAAkB,SAAkB,KAAuB,sBAAgC;AACzG,QAAM,EAAE,OAAO,MAAAC,OAAM,QAAQ,IAAI,QAAQ,QAAQ,CAAC;AAClD,QAAM,EAAE,YAAY,QAAQ,aAAa,KAAK,IAAI,QAAQ,WAAW,CAAC;AACtE,QAAM,YAAY,IAAI,UAAU,YAAY;AAE5C,QAAM,YAAY,sCAAiC,IAAI,YAAY,IAAI;AACvE,QAAM,EAAE,SAAS,IAAI,aAAa,CAAC;AACnC,QAAM,qBAAqB,CAAC,GAAG,YAAY,GAAG,oBAAoB;AAGlE,MAAI,CAAC,QAAQ,MAAM,SAAS,SAAS,KAAK,CAAC,QAAQ,MAAM,sBAAkB,GAAG;AAC5E,WAAO;AAAA,EACT;AAGA,MAAI,QAAQ,SAAS,IAAI,MAAM;AAC7B,WAAO;AAAA,EACT;AAGA,MAAIA,UAAS,IAAI,KAAK,MAAM;AAC1B,WAAO;AAAA,EACT;AAGA,MAAI,SAAS,UAAU,IAAI,KAAK,OAAO;AACrC,WAAO;AAAA,EACT;AAGA,MAAI,WAAW,YAAY,IAAI,KAAK,SAAS;AAC3C,WAAO;AAAA,EACT;AAGA,MAAI,mBAAmB,UAAU,CAAC,mBAAmB,SAAS,IAAI,aAAa,EAAE,GAAG;AAClF,mBAAO,MAAM,0BAA0B;AACvC,WAAO;AAAA,EACT;AAGA,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,UAAM,UAAU,UAAU,SAAS,GAAG;AAGtC,QAAI,CAAC,SAAS;AACZ,qBAAO,MAAM,SAAS,GAAG,iBAAiB;AAC1C,aAAO;AAAA,IACT;AAGA,QAAI,SAAS,YAAY,OAAO;AAC9B,qBAAO,MAAM,GAAG,OAAO,mBAAmB,KAAK,EAAE;AACjD,aAAO;AAAA,IACT;AAAA,EACF;AAGA,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,WAAW,GAAG;AACtD,UAAM,UAAU,UAAU,cAAc,GAAG;AAG3C,QAAI,CAAC,SAAS;AACZ,qBAAO,MAAM,cAAc,GAAG,iBAAiB;AAC/C,aAAO;AAAA,IACT;AAGA,QAAI,SAAS,YAAY,OAAO;AAC9B,qBAAO,MAAM,GAAG,OAAO,mBAAmB,KAAK,EAAE;AACjD,aAAO;AAAA,IACT;AAAA,EACF;AAGA,SAAO;AACT;;;ACtFA,mBAAsC;AAS/B,IAAM,oBAAN,MAAoD;AAAA,EACzD;AAAA,EAEA;AAAA,EAEA,IAAI,oBAAoB;AACtB,WAAO,CAAC,KAAK,OAAO;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,WAAW;AACb,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,cAAc;AAChB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,UAAU;AACZ,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,OAA4B;AACtC,SAAK,SAAS;AAGd,QAAI,MAAM,UAAU,YAAY,6BAAwB;AACtD,WAAK,UAAM,oBAAM,MAAM,SAAc;AAAA,IACvC,OAAO;AAEL,WAAK,UAAM,oBAAM,MAAM,MAAM;AAAA,IAC/B;AAEA,QAAI,CAAC,KAAK,KAAK;AACb,YAAM,IAAI,MAAM,yDAAyD;AAAA,IAC3E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAQ,CAAC,QAAwB;AAC/B,SAAK,UAAM,6BAAe,KAAK,KAAK,GAAG;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,CAAC,KAAa,UAAkB;AACzC,UAAM,MAAM,KAAK;AAEjB,QAAI,WAAW,IAAI,YAAY,CAAC;AAChC,QAAI,SAAS,SAAS,IAAI,SAAS,UAAU,CAAC;AAC9C,QAAI,SAAS,OAAO,GAAG,IAAI;AAE3B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,CAAC,KAAa,UAAkB;AAC9C,UAAM,MAAM,KAAK;AAEjB,QAAI,WAAW,IAAI,YAAY,CAAC;AAChC,QAAI,SAAS,cAAc,IAAI,SAAS,eAAe,CAAC;AACxD,QAAI,SAAS,YAAY,GAAG,IAAI;AAEhC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAc,CAAC,QAAgB;AAC7B,QAAI,KAAK,IAAI,UAAU,SAAS,GAAG,GAAG;AACpC,aAAO,KAAK,IAAI,SAAS,OAAO,GAAG;AAAA,IACrC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAmB,CAAC,QAAgB;AAClC,QAAI,KAAK,IAAI,UAAU,cAAc,GAAG,GAAG;AACzC,aAAO,KAAK,IAAI,SAAS,YAAY,GAAG;AAAA,IAC1C;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,CAAC,QAAgB;AAC1B,WAAO,KAAK,IAAI,UAAU,SAAS,GAAG,MAAM;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,CAAC,QAAgB;AAC/B,WAAO,KAAK,IAAI,UAAU,cAAc,GAAG,MAAM;AAAA,EACnD;AACF;;;ACxJA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMO,IAAM,UAAU;AAOhB,SAAS,mBAAmB,KAAwC,MAAgB;AACzF,MAAI,OAAO,IAAI,QAAQ,CAAC;AACxB,aAAW,OAAO,IAAI,MAAM;AAC1B,UAAM,QAAQ,IAAI,KAAK,GAAG;AAE1B,QAAI,KAAK,GAAG,IAAI,KAAK,SAAS,GAAG,IAAI,QAAQ,aAAa,KAAK;AAAA,EACjE;AACF;AAOO,SAAS,qBAAqB,KAAwC;AAC3E,QAAM,OAAiB,CAAC;AAExB,MAAI,OAAO,IAAI,QAAQ,CAAC;AACxB,aAAW,OAAO,IAAI,MAAM;AAC1B,QAAI,IAAI,KAAK,GAAG,KAAK,QAAW;AAC9B,UAAI,KAAK,GAAG,IAAI;AAAA,IAClB,OAAO;AACL,YAAM,UAAU,aAAa,IAAI,KAAK,GAAG,CAAC;AAC1C,UAAI,QAAQ,KAAK,OAAO,GAAG;AAEzB,YAAI,KAAK,GAAG,IAAI;AAAA,MAClB,OAAO;AACL,aAAK,KAAK,GAAG;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACA,iBAAI,MAAM,oCAAoC,IAAI,sCAAsC;AACxF,SAAO;AACT;AAGO,SAAS,aAAa,MAAc;AACzC,SAAO,OAAO,KAAK,MAAM,QAAQ,EAAE,SAAS,OAAO;AACrD;AAGO,SAAS,aAAa,MAAc;AACzC,SAAO,OAAO,KAAK,IAAI,EAAE,SAAS,QAAQ;AAC5C;;;ALzCA,eAAsB,gBACpB,QACA,cACA,KACA,aACyB;AACzB,QAAM,UAAU,IAAI,kBAAkB,GAAG;AACzC,QAAM,WAA2B;AAAA,IAC/B,KAAK,IAAI;AAAA,IACT,UAAU,CAAC;AAAA,IACX,SAAS;AAAA,EACX;AAGA,MAAI,gBAAgB;AAGpB,MAAI,aAAuB,CAAC;AAG5B,QAAM,WAAW,IAAI,KAAK,WAAW,QAAQ,IAAI,KAAK,QAAQ;AAC9D,MAAI,UAAU;AACZ,iBAAa,qBAAqB,QAAQ,GAA6B;AAAA,EACzE;AAEA,iBAAI,KAAK,aAAa,oBAAoB;AAE1C,aAAW,EAAE,MAAM,UAAU,WAAW,KAAK,cAAc;AACzD,UAAM,iBAAiB,EAAE,GAAG,aAAa,KAAK;AAE9C,eAAW,UAAU,UAAU;AAE7B,UAAI,CAAC,OAAO,gBAAgB;AAC1B;AAAA,MACF;AAGA,UAAI,kBAAkB,QAAQ,KAAK,UAAU,GAAG;AAC9C;AAAA,MACF;AAEA,YAAM,QAAQ,OAAO,eAAe;AACpC,qBAAI,KAAK,gBAAgB,6BAA6B,KAAK,EAAE;AAE7D,sBAAgB;AAIhB,YAAM,eAAe,CAAC,WAAmB;AAEvC,YAAI,IAAI,aAAa,UAAU;AAC7B;AAAA,QACF;AAEA,cAAM,aAAa,GAAG,OAAO,IAAI,aAAa,IAAI;AAClD,gBAAQ,IAAI,WAAW,QAAQ,IAAI,YAAY,CAAC;AAChD,gBAAQ,IAAI,SAAS,cAAc,QAAQ,IAAI,SAAS,eAAe,CAAC;AACxE,gBAAQ,IAAI,SAAS,YAAY,UAAU,IAAI;AAAA,MACjD;AAEA,mBAAa,SAAS;AAEtB,UAAI;AAEF,cAAM,OAAO,eAAe,OAAO;AAEnC,uBAAI,KAAK,gBAAgB,kBAAkB;AAG3C,qBAAa,WAAW;AAAA,MAC1B,SAAS,GAAG;AACV,uBAAI,KAAK,gBAAgB,kBAAkB,CAAC,EAAE;AAC9C,qBAAa,SAAS;AAGtB,iBAAS,WAAW,SAAS,YAAY,CAAC;AAC1C,iBAAS,SAAS,KAAK,kBAAkB,CAAC,EAAE;AAE5C,gBAAQ,OAAO,SAAS;AAAA,UACtB,KAAK,OAAO;AACV,2BAAI,MAAM,gBAAgB,kBAAkB,CAAC,EAAE;AAC/C,qBAAS,SAAS;AAClB,mBAAO;AAAA,UAET,KAAK,OAAO;AACV,qBAAS,mBAAmB,SAAS,oBAAoB,CAAC;AAC1D,qBAAS,iBAAiB,KAAK,IAAI,CAAC,IAAI;AACxC;AAAA,QACJ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,WAAS,UAAU;AAGnB,MAAI,CAAC,eAAe;AAClB,mBAAI,KAAK,aAAa,2BAA2B;AACjD,WAAO;AAAA,EACT;AAGA,MAAI,IAAI,aAAa,UAAU;AAC7B,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,QAAQ;AAG5B,MAAI,UAAU;AACZ,uBAAmB,aAAuC,UAAU;AAAA,EACtE;AAGA,QAAM,UAAU,uBAAAC,QAAU,QAAQ,IAAI,QAAQ,WAAW;AAGzD,MAAI,QAAQ,SAAS,GAAG;AACtB,aAAS,YAAY;AAGrB,aAAS,QAAQ,aAAa,KAAK,UAAU,OAAO,CAAC;AAAA,EACvD;AAGA,MAAI,SAAS,YAAY,SAAS,SAAS,SAAS,GAAG;AACrD,WAAO,SAAS;AAAA,EAClB;AAEA,iBAAI,MAAM,EAAE,GAAG,aAAa,QAAQ,GAAG,mBAAmB;AAE1D,SAAO;AACT;;;AM7IA,IAAAC,gBAAsB;AAQf,IAAM,sBAAN,MAAsD;AAAA,EAC3D;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,cAAc;AAChB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,UAAU;AACZ,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,OAA4B;AACtC,SAAK,SAAS;AAGd,QAAI,MAAM,UAAU,YAAY,6BAAwB;AACtD,WAAK,UAAM,qBAAM,MAAM,SAAc;AAAA,IACvC,OAAO;AAEL,WAAK,UAAM,qBAAM,MAAM,MAAM;AAAA,IAC/B;AAEA,QAAI,CAAC,KAAK,KAAK;AACb,YAAM,IAAI,MAAM,wDAAwD;AAAA,IAC1E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,CAAC,QAAgB;AAC1B,WAAO,KAAK,IAAI,UAAU,SAAS,GAAG,MAAM;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,CAAC,QAAgB;AAC/B,WAAO,KAAK,IAAI,UAAU,cAAc,GAAG,MAAM;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU,MAA8B;AACtC,WAAO;AAAA,MACL,SAAS;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,CAAC,eAAwB,eAAgD;AAC9E,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;;;ACzFA,eAAsB,kBACpB,cACA,KACA,aAC2B;AAC3B,QAAM,UAAU,IAAI,oBAAoB,GAAG;AAC3C,QAAM,WAA6B;AAAA,IACjC,KAAK,IAAI;AAAA,IACT,SAAS;AAAA;AAAA,EACX;AAGA,QAAM,WAAW,IAAI,KAAK,WAAW,QAAQ,IAAI,KAAK,QAAQ;AAC9D,MAAI,UAAU;AACZ,yBAAqB,QAAQ,GAA6B;AAAA,EAC5D;AAEA,iBAAI,KAAK,aAAa,+BAA+B;AAErD,aAAW,EAAE,MAAM,UAAU,WAAW,KAAK,cAAc;AACzD,UAAM,iBAAiB,EAAE,GAAG,aAAa,KAAK;AAE9C,eAAW,UAAU,UAAU;AAE7B,UAAI,CAAC,OAAO,kBAAkB;AAC5B;AAAA,MACF;AAGA,UAAI,kBAAkB,QAAQ,KAAK,UAAU,GAAG;AAC9C;AAAA,MACF;AAEA,YAAM,QAAQ,OAAO,iBAAiB;AACtC,qBAAI,KAAK,gBAAgB,6BAA6B,KAAK,EAAE;AAE7D,UAAI;AAEF,cAAM,OAAO,MAAM,OAAO,iBAAiB,OAAO;AAClD,iBAAS,UAAU,KAAK;AAGxB,YAAI,KAAK,cAAc,KAAK,eAAe;AACzC,mBAAS,SAAS;AAAA,YAChB,MAAM,KAAK,cAAc;AAAA,YACzB,SAAS,KAAK,iBAAiB,yBAAyB,IAAI;AAAA,UAC9D;AAAA,QACF;AAEA,uBAAI,KAAK,gBAAgB,gCAAgC,KAAK,UAAU,YAAY,QAAQ,EAAE;AAAA,MAChG,SAAS,GAAG;AAEV,uBAAI,MAAM,gBAAgB,kBAAkB,CAAC,EAAE;AAC/C,iBAAS,UAAU;AACnB,iBAAS,SAAS;AAAA,UAChB,MAAM;AAAA,UACN,SAAS,6BAA6B,CAAC;AAAA,QACzC;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACxEA,IAAAC,mCAAoB;AACpB,IAAAC,gBAA2B;AAQ3B,IAAM,YAAY;AAClB,IAAM,kBAAkB;AAEjB,IAAM,sBAAN,MAA0B;AAAA,EAC/B;AAAA,EACA,UAAmC,CAAC;AAAA,EACpC;AAAA,EACA;AAAA,EAEA,YAAY,QAAsB,cAA4B,SAAsB;AAClF,SAAK,WAAW;AAGhB,SAAK,QAAQ,QAAQ,OAAO,IAAI;AAGhC,eAAW,EAAE,MAAM,cAAc,KAAK,cAAc;AAElD,YAAM,EAAE,MAAM,IAAI,cAAc;AAGhC,YAAM,eAAe,KAAK,MAAM,IAAI,CAAC;AAGrC,WAAK,QAAQ,IAAI,IAAI;AAAA,IACvB;AAGA;AAAA,MACE,UACE,sCAAI,SAAS,EACV,YAAY,SAAS,EACrB,IAAI,KAAK,KAAK,EAEd,KAAK,KAAK,WAAW,EAErB,MAAM,KAAK,oBAAoB;AAAA,MACpC,KAAK,OAAO,IAAI;AAAA,IAClB;AAAA,EACF;AAAA,EAEA,cAAc,MAAM;AAClB,aAAK,sCAAI,WAAW,EAAE,MAAM,KAAK,OAAO,UAAU,CAAC,EAAE,MAAM,KAAK,QAAQ;AAAA,EAC1E;AAAA,EAEA,WAAW,CAAC,UAAqB;AAC/B,mBAAI,MAAM,OAAO,mBAAmB;AAGpC,UAAM,YAAY,MAAM;AAEtB,YAAM,OAAkB,MAAM,QAAQ,CAAC;AAGvC,iBAAW,QAAQ,OAAO,KAAK,KAAK,OAAO,GAAG;AAE5C,cAAM,SAAS,GAAG,IAAI,IAAI;AAG1B,cAAM,WAAsB,CAAC;AAG7B,mBAAW,OAAO,OAAO,KAAK,IAAI,GAAG;AAEnC,kBAAI,0BAAW,MAAM,GAAG,GAAG;AAEzB,qBAAS,IAAI,MAAM,MAAM,CAAC,IAAI,KAAK,GAAG;AAAA,UACxC;AAAA,QACF;AAGA,aAAK,QAAQ,IAAI,EAAE,QAAQ,QAAQ;AAAA,MACrC;AAGA,UAAI,KAAK,UAAU;AACjB,aAAK,SAAS;AACd,aAAK,WAAW;AAAA,MAClB;AAAA,IACF;AAGA,iBAAa,KAAK,aAAa;AAC/B,SAAK,gBAAgB,WAAW,WAAW,eAAe;AAAA,EAC5D;AAAA,EAEA,QAAQ,CAAC,mBAA2B;AAClC,UAAM,YAAuC,CAAC;AAG9C,UAAM,YAAY,CAAC,IAAY,KAAe,QAAiB;AAC7D,UAAI,OAAO,OAAO;AAChB,cAAM,OAAO,SAAS,cAAc,IAAI,GAAG;AAC3C,cAAM,QAAQ,OAAO;AACrB,cAAM,WAAW,CAAC,IAAI,MAAM,KAAK,EAAE,KAAK,GAAG;AAG3C,kBAAU,QAAQ,IAAI,EAAE,IAAI,MAAM,MAAM;AAExC;AAAA,MACF;AAEA,UAAI,OAAO,UAAU;AACnB,YAAI,IAAI,SAAS,GAAG;AAClB,gBAAM,IAAI,MAAM,sCAAsC;AAAA,QACxD;AAEA,mBAAW,KAAK,KAAK;AACnB,gBAAM,OAAO,SAAS,cAAc,IAAI,CAAC;AACzC,gBAAM,WAAW,CAAC,IAAI,IAAI,EAAE,KAAK,GAAG;AAGpC,oBAAU,QAAQ,IAAI,EAAE,IAAI,KAAK;AAAA,QACnC;AAEA;AAAA,MACF;AAGA,YAAM,IAAI,MAAM,0BAA0B,EAAE,EAAE;AAAA,IAChD;AAGA,UAAM,aAAa,YAAY;AAC7B,YAAM,UAAU,OAAO,KAAK,SAAS;AACrC,YAAM,UAAU,OAAO,OAAO,SAAS;AAGvC,iBAAW,OAAO,SAAS;AACzB,eAAO,UAAU,GAAG;AAAA,MACtB;AAEA,UAAI;AAEF,kBAAM,sCAAI,WAAW,EAAE,WAAW,MAAM,KAAK,MAAM,CAAC,EAAE,MAAM,OAAO;AAAA,MACrE,SAAS,KAAK;AACZ,uBAAI,MAAM,KAAK,2BAA2B;AAG1C,mBAAW,OAAO,SAAS;AACzB,oBAAU,GAAG,IAAI,QAAQ,OAAO,GAAG,CAAC;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAGA,UAAM,SAAqB,OAAO,IAAY,KAAe,QAAiB;AAC5E,gBAAU,IAAI,KAAK,GAAG;AAAA,IACxB;AAGA,gBAAY,MAAM;AAChB,UAAI,OAAO,KAAK,SAAS,EAAE,SAAS,GAAG;AACrC,uBAAI,MAAM,WAAW,+BAA+B;AACpD,aAAK,WAAW;AAAA,MAClB;AAAA,IACF,GAAG,eAAe;AAElB,WAAO;AAAA,EACT;AAAA,EAEA,uBAAuB,OAAO,MAAe;AAC3C,mBAAI,KAAK,mCAAmC;AAC5C,mBAAI,MAAM,CAAC;AAEX,QAAI;AACF,gBAAM,sCAAI,SAAS,EAAE,MAAM;AAAA,QACzB,UAAU;AAAA,UACR,MAAM,KAAK;AAAA,UACX;AAAA,QACF;AAAA,QACA,MAAM;AAAA;AAAA,UAEJ,wBAAwB;AAAA,QAC1B;AAAA,MACF,CAAC;AAGD,WAAK,YAAY;AAAA,IACnB,SAAS,KAAK;AACZ,qBAAI,MAAM,KAAK,6BAA6B;AAAA,IAC9C;AAAA,EACF;AACF;;;AVpLO,IAAM,aAAN,MAAM,YAAW;AAAA;AAAA,EAEtB,WAAW;AAAA;AAAA,EAGX,oBAAoB,IAAI,iBAAiB,MAAM;AAAA;AAAA,EAG/C,SAAS;AAAA;AAAA,EAGA,WAAO,eAAAC,SAAQ;AAAA;AAAA,EAGf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YACE,QACA,cACA,YACA,WACA,SACA;AACA,SAAK,UAAU;AACf,SAAK,gBAAgB;AAGrB,QAAI,oBAAoB,QAAQ,cAAc,MAAM;AAClD,WAAK,eAAe;AACpB,iBAAW,QAAQ;AACnB,qBAAI,KAAK,oCAA+B;AAAA,IAC1C,CAAC;AAGD,SAAK,KAAK,IAAI,YAAW,OAAO;AAGhC,SAAK,KAAK,IAAI,eAAAA,QAAQ,KAAK,EAAE,OAAO,MAAM,CAAC,CAAC;AAE5C,QAAI,YAAY;AACd,qBAAI,KAAK,qBAAqB,UAAU,EAAE;AAC1C,WAAK,cAAc;AAAA,IACrB;AAEA,QAAI,WAAW;AACb,qBAAI,KAAK,oBAAoB,SAAS,EAAE;AACxC,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA;AAAA,EAGA,cAAc,CAAC,SAAiB;AAC9B,QAAI,KAAK,UAAU;AACjB,YAAM,IAAI,MAAM,iFAAiF;AAAA,IACnG;AAGA,UAAM,UAAU;AAAA,MACd,KAAK,UAAAC,QAAG,aAAa,QAAQ,IAAI,gBAAgB,oBAAoB;AAAA,MACrE,MAAM,UAAAA,QAAG,aAAa,QAAQ,IAAI,iBAAiB,oBAAoB;AAAA,IACzE;AAGA,QAAI,CAAC,YAAY,GAAG;AAElB,WAAK,SAAS,QAAQ,IAAI,kBAAkB,UAAAA,QAAG,aAAa,sBAAsB,EAAE,SAAS,EAAE,KAAK;AACpG,qBAAI,KAAK,oBAAoB,KAAK,MAAM,EAAE;AAE1C,UAAI,CAAC,KAAK,QAAQ;AAChB,cAAM,IAAI,MAAM,qBAAqB;AAAA,MACvC;AAAA,IACF;AAGA,UAAM,SAAS,aAAAC,QAAM,aAAa,SAAS,KAAK,IAAI,EAAE,OAAO,IAAI;AAGjE,WAAO,GAAG,aAAa,MAAM;AAC3B,qBAAI,KAAK,4BAA4B,IAAI,EAAE;AAE3C,WAAK,WAAW;AAAA,IAClB,CAAC;AAGD,WAAO,GAAG,SAAS,CAAC,MAAwB;AAC1C,UAAI,EAAE,SAAS,cAAc;AAC3B,uBAAI;AAAA,UACF,mEAAmE,IAAI,kCAAkC,IAAI;AAAA,QAC/G;AACA,mBAAW,MAAM;AACf,iBAAO,MAAM;AACb,iBAAO,OAAO,IAAI;AAAA,QACpB,GAAG,GAAI;AAAA,MACT;AAAA,IACF,CAAC;AAGD,YAAQ,GAAG,WAAW,MAAM;AAC1B,qBAAI,KAAK,kCAAkC;AAC3C,aAAO,MAAM,MAAM;AACjB,uBAAI,KAAK,eAAe;AACxB,gBAAQ,KAAK,CAAC;AAAA,MAChB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,iBAAiB,MAAM;AAErB,SAAK,KAAK,IAAI,YAAY,YAAW,QAAQ;AAG7C,SAAK,KAAK,IAAI,YAAY,KAAK,QAAQ;AAEvC,QAAI,YAAY,GAAG;AACjB;AAAA,IACF;AAGA,SAAK,KAAK,IAAI,CAAC,kBAAkB,kBAAkB,GAAG,KAAK,cAAc;AAGzE,SAAK,KAAK,KAAK,kBAAkB,KAAK,cAAc,QAAQ,CAAC;AAG7D,SAAK,KAAK,KAAK,oBAAoB,KAAK,cAAc,UAAU,CAAC;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,iBAAiB,CAAC,KAAsB,KAAuB,SAAuB;AAEpF,UAAM,EAAE,MAAM,IAAI,IAAI;AACtB,QAAI,UAAU,KAAK,QAAQ;AACzB,YAAM,MAAM,gCAAgC,MAAM,QAAQ,UAAU,GAAG,CAAC;AACxE,qBAAI,KAAK,GAAG;AACZ,UAAI,OAAO,GAAG,EAAE,KAAK,GAAG;AACxB,WAAK,kBAAkB,MAAM;AAC7B;AAAA,IACF;AAGA,SAAK;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,OAAO,KAAsB,QAA0B;AAChE,QAAI;AACF,UAAI,KAAK,MAAM,KAAK,kBAAkB,WAAW,CAAC;AAAA,IACpD,SAAS,KAAK;AACZ,qBAAI,MAAM,GAAG;AACb,UAAI,OAAO,GAAG,EAAE,KAAK,uBAAuB;AAAA,IAC9C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,CAAC,kBAAyC;AAExD,WAAO,OAAO,KAAsB,QAA0B;AAE5D,YAAM,YAAY,iBAAiB,aAAa;AAEhD,UAAI;AAEF,cAAM,UAA4B,IAAI,MAAM,WAAY,CAAC;AAGzD,aAAK,eAAe,KAAK,YAAY,WAAW,CAAC,CAAC;AAGlD,cAAM,OAAO,SAAS,OAAO,IAAI,QAAQ,IAAI,KAAK;AAClD,cAAMC,aAAY,SAAS,aAAa;AACxC,cAAM,MAAM,SAAS,QAAQ,EAAE,OAAO,IAAI,SAAS,IAAI,MAAM,GAAG;AAEhE,cAAM,cAAc;AAAA,UAClB,KAAK,QAAQ;AAAA,UACb,WAAAA;AAAA,UACA;AAAA,QACF;AAEA,uBAAI,KAAK,EAAE,GAAG,aAAa,KAAK,WAAW,QAAQ,WAAW,cAAc,GAAG,kBAAkB;AACjG,uBAAI,MAAM,EAAE,GAAG,aAAa,QAAQ,GAAG,uBAAuB;AAG9D,YAAI;AAGJ,YAAI,kBAAkB,UAAU;AAC9B,qBAAW,MAAM,gBAAgB,KAAK,SAAS,KAAK,eAAe,SAAS,WAAW;AAAA,QACzF,OAAO;AACL,qBAAW,MAAM,kBAAkB,KAAK,eAAe,SAAS,WAAW;AAAA,QAC7E;AAGA,aAAK,cAAc,KAAK,WAAW,QAAQ;AAG3C,uBAAI,MAAM,EAAE,GAAG,aAAa,SAAS,GAAG,mBAAmB;AAG3D,YAAI,KAAK;AAAA,UACP,YAAY;AAAA,UACZ,MAAM;AAAA,UACN;AAAA,QACF,CAAC;AACD,aAAK,kBAAkB,WAAW,WAAW,aAAa;AAAA,MAC5D,SAAS,KAAK;AACZ,uBAAI,MAAM,GAAG;AACb,YAAI,OAAO,GAAG,EAAE,KAAK,uBAAuB;AAC5C,aAAK,kBAAkB,MAAM;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,QAAQ,KAAsB,KAAuB,MAA4B;AACtF,UAAM,YAAY,KAAK,IAAI;AAE3B,QAAI,GAAG,UAAU,MAAM;AACrB,YAAM,cAAc,KAAK,IAAI,IAAI;AACjC,YAAM,UAAU;AAAA,QACd,KAAK,IAAI,MAAM,SAAS;AAAA,QACxB,QAAQ,IAAI;AAAA,QACZ,KAAK,IAAI;AAAA,QACT,QAAQ,IAAI;AAAA,QACZ,UAAU,GAAG,WAAW;AAAA,MAC1B;AAEA,UAAI,cAAc,MAAM,eAAI,KAAK,OAAO,IAAI,eAAI,KAAK,OAAO;AAAA,IAC9D,CAAC;AAED,SAAK;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,SAAS,KAAsB,KAAuB;AAC3D,QAAI;AACF,UAAI,KAAK,IAAI;AAAA,IACf,SAAS,KAAK;AACZ,qBAAI,MAAM,GAAG;AACb,UAAI,OAAO,GAAG,EAAE,KAAK,uBAAuB;AAAA,IAC9C;AAAA,EACF;AACF;;;AW5RA,IAAAC,mCAAoB;AACpB,IAAAC,gBAA2B;AAOpB,SAAS,WAAW,cAA4B;AACrD,eACG,QAAQ,OAAK,EAAE,QAAQ,EACvB,OAAO,aAAW,QAAQ,OAAO,EACjC,QAAQ,UAAU;AACvB;AAEA,eAAe,WAAW,SAAkB;AAE1C,QAAM,kBAAkB;AAAA,IACtB,sBAAa,GAAG,CAAC,yBAAW,KAAK;AAAA,IACjC,sBAAa,GAAG,CAAC,yBAAW,QAAQ;AAAA,IACpC,sCAAqB,GAAG,CAAC,yBAAW,OAAO,yBAAW,QAAQ;AAAA,IAC9D,sBAAa,GAAG,CAAC,yBAAW,OAAO;AAAA,IACnC,cAAU,GAAG,CAAC,yBAAW,OAAO,yBAAW,UAAU,yBAAW,OAAO;AAAA,EACzE;AAGA,QAAM,aAA2B,gBAAgB,QAAQ,KAAK,KAAK,6BAAyB;AAE5F,QAAM,WAAqB;AAAA,IACzB,UAAU;AAAA,IACV,eAAe;AAAA,IACf,UAAU,GAAG;AAEX,qBAAI,MAAM,GAAG,0CAA0C;AACvD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAGA,YAAM,sCAAI,QAAQ,OAAO,QAAQ,OAAO,EAAE,MAAM,CAAC,KAAK,SAAS;AAE7D,QAAI,WAAW,SAAS,IAAI,GAAG;AAC7B,UAAI;AAEF,aAAK,QAAQ,gBAAgB,KAAK,IAAI;AAAA,MACxC,SAAS,GAAG;AAEV,uBAAI,MAAM,GAAG,gCAAgC;AAAA,MAC/C;AAAA,IACF;AAAA,EACF,GAAG,QAAQ;AACb;;;AZNO,IAAM,cAAc,MAAM,QAAQ,IAAI,oBAAoB;AAG1D,IAAM,cAAc,MAAM,QAAQ,IAAI,cAAc;AAEpD,IAAM,YAAY,MAAM,QAAQ,IAAI,cAAc;AAElD,IAAM,aAAN,MAAiB;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YAAY,EAAE,aAAa,KAAK,GAAgB,eAA6B,CAAC,GAAG,OAA0B,CAAC,GAAG;AAC7G,UAAM,aAAuB,qBAAM,IAAI;AACvC,WAAO,cAAc;AAGrB,kBAAc,OAAO,OAAO;AAG5B,QAAI,YAAY,GAAG;AAEjB,UAAI,CAAC,QAAQ,MAAM;AACjB,cAAM,IAAI,MAAM,6BAA6B;AAAA,MAC/C;AAEA,YAAM,uBAA2C,CAAC;AAGlD,iBAAW,cAAc,cAAc;AAErC,6BAAqB,KAAK;AAAA,UACxB,MAAM,WAAW;AAAA,UACjB,aAAa,WAAW;AAAA,UACxB,YAAY,WAAW;AAAA,UACvB,UAAU,WAAW;AAAA,QACvB,CAAC;AAAA,MACH;AAGA,cAAQ,KAAK,oBAAoB;AAEjC;AAAA,IACF;AAEA,SAAK,cAAc,IAAI,WAAW,QAAQ,cAAc,KAAK,YAAY,KAAK,WAAW,MAAM;AAE7F,UAAI,YAAY,KAAK,UAAU,GAAG;AAChC,mBAAW,YAAY;AAAA,MACzB;AAAA,IACF,CAAC;AAGD,QAAI,KAAK,YAAY;AACnB;AAAA,IACF;AAEA,SAAK,MAAM;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAQ,CAAC,OAAO,QAAS;AACvB,SAAK,YAAY,YAAY,IAAI;AAAA,EACnC;AACF;;;AavHA,IAAAC,gBAAsB;AA8Cf,IAAM,UAAN,MAAmC;AAAA,EACxC,SAAoB,CAAC;AAAA,EACrB;AAAA,EACA,eAA6C,CAAC;AAAA,EAC9C,gBAAgB;AAAA,EAChB,iBAAiC,CAAC;AAAA,EAElC,iBAAiB,CAAC,SAAqB;AACrC,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,UAAU,CAAC,SAAoB;AAC7B,mBAAI,MAAM,MAAM,0BAA0B;AAC1C,SAAK,SAAS,QAAQ,CAAC;AAEvB,SAAK,SAAS;AAGd,eAAW,OAAO,KAAK,cAAc;AAEnC,WAAK,aAAa,GAAG,MAAE,qBAAM,KAAK,MAAM,CAAC;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,UAAU,CAAC,QAAgB;AAEzB,WAAO,KAAK,OAAO,GAAG,KAAK;AAAA,EAC7B;AAAA,EAEA,QAAQ,MAAM;AACZ,SAAK,gBAAgB,UAAU,OAAO,KAAK,KAAK,MAAM,CAAC;AAAA,EACzD;AAAA,EAEA,aAAa,CAAC,QAAgB;AAC5B,SAAK,gBAAgB,UAAU,CAAC,GAAG,CAAC;AAAA,EACtC;AAAA,EAEA,UAAU,CAAC,KAAa,UAAkB;AACxC,SAAK,gBAAgB,OAAO,CAAC,GAAG,GAAG,KAAK;AAAA,EAC1C;AAAA,EAEA,YAAY,CAAC,eAA6B;AACxC,UAAM,MAAM,KAAK;AACjB,SAAK,aAAa,GAAG,IAAI;AACzB,WAAO,MAAM,KAAK,YAAY,GAAG;AAAA,EACnC;AAAA,EAEA,UAAU,CAAC,aAA2B;AACpC,SAAK,eAAe,KAAK,QAAQ;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,CAAC,QAAgB;AAC7B,WAAO,KAAK,aAAa,GAAG;AAAA,EAC9B;AAAA,EAEA,WAAW,MAAM;AAEf,eAAW,WAAW,KAAK,gBAAgB;AACzC,kBAAQ,qBAAM,KAAK,MAAM,CAAC;AAAA,IAC5B;AAGA,SAAK,WAAW,MAAM;AAAA,IAAC;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,kBAAkB,CAAC,IAAY,MAAgB,UAAmB;AAChE,SAAK,MAAM,IAAI,MAAM,KAAK;AAAA,EAC5B;AACF;;;AfvGA,IAAM,oBAAoB,YAAY,KAAK,CAAC,YAAY;AACxD,IAAM,gBAAgB,YAAY,KAAK,YAAY,KAAK,UAAU;AAK3D,IAAM,aAAN,MAA6C;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAuB,CAAC;AAAA,EACxB,SAAS,IAAI,QAAQ;AAAA,EACrB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASd,QAAmB;AAAA,IACjB,OAAO,KAAK,OAAO;AAAA,IACnB,SAAS,KAAK,OAAO;AAAA,IACrB,YAAY,KAAK,OAAO;AAAA,IACxB,SAAS,KAAK,OAAO;AAAA,IACrB,WAAW,KAAK,OAAO;AAAA,IACvB,SAAS,KAAK,OAAO;AAAA,EACvB;AAAA,EAEA,IAAI,WAAW;AACb,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,OAAO;AACT,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,cAAc;AAChB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,aAAa;AACf,WAAO,KAAK,eAAe,CAAC;AAAA,EAC9B;AAAA,EAEA,YAAY,KAAoB;AAC9B,SAAK,QAAQ,IAAI;AACjB,SAAK,eAAe,IAAI;AACxB,SAAK,cAAc,IAAI;AAEvB,mBAAI,KAAK,cAAc,KAAK,KAAK,aAAa;AAC9C,mBAAI,MAAM,GAAG;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAgB,MAAM;AACpB,mBAAI,KAAK,yBAAyB,KAAK,KAAK,EAAE;AAE9C,QAAI,KAAK,aAAa;AACpB,YAAM,IAAI,MAAM,gCAAgC,KAAK,KAAK,EAAE;AAAA,IAC9D;AAEA,SAAK,cAAc;AAGnB,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,CAAyB,OAAUC,UAA6C;AACrF,UAAM,kBAAc,0DAAwB,MAAM,IAAI;AAGtD,QAAI,CAAC,eAAe,CAACA,OAAM;AACzB,YAAM,IAAI,MAAM,0BAA0B,MAAM,IAAI,EAAE;AAAA,IACxD;AAEA,UAAM,UAAmB;AAAA,MACvB;AAAA;AAAA,MAEA,MAAMA,SAAQ;AAAA,MACd;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,YAAY,CAAC;AAAA,QACb,QAAQ,CAAC;AAAA,QACT,aAAa,CAAC;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,WAAW,KAAK;AACtB,UAAM,SAAS,GAAG,KAAK,KAAK,KAAK,MAAM,IAAI;AAC3C,UAAM,cAAc,EAAE,WAAW,gBAAgB,QAAQ,UAAU,MAAM;AACzE,UAAM,aAAa,CAAC,UAAkB,OAAO,KAAK,KAAK,EAAE,SAAS;AAClE,UAAM,MAAM,CAAC,SAAiB,aAAqB;AACjD,YAAM,kBAAc,sBAAO,YAAY,QAAQ,OAAO;AAEtD,qBAAI,KAAK,GAAG,OAAO,mBAAmB,QAAQ,KAAK,IAAI,MAAM;AAC7D,qBAAI,KAAK,aAAa,MAAM;AAC5B,qBAAI,MAAM,UAAU,MAAM;AAAA,IAC5B;AAEA,aAAS,SAAS,kBAA6D;AAC7E,UAAI,mBAAmB;AACrB,YAAI,mBAAmB,iBAAiB,SAAS,CAAC;AAIlD,iBAAS,KAAK;AAAA,UACZ,GAAG;AAAA,UACH,YAAY;AAAA,UACZ;AAAA,QACF,CAAC;AAAA,MACH;AAEA,aAAO,EAAE,MAAM;AAAA,IACjB;AAEA,aAAS,OAAO,gBAAuD;AACrE,UAAI,mBAAmB;AACrB,YAAI,iBAAiB,eAAe,SAAS,CAAC;AAI9C,iBAAS,KAAK;AAAA,UACZ,GAAG;AAAA,UACH,UAAU;AAAA,UACV;AAAA,QACF,CAAC;AAAA,MACH;AAGA,aAAO,EAAE,OAAO,SAAS;AAAA,IAC3B;AAEA,aAAS,MAAM,eAA+B;AAC5C,UAAI,eAAe;AACjB,YAAI,gBAAgB,cAAc,SAAS,CAAC;AAE5C,iBAAS,KAAK;AAAA,UACZ,GAAG;AAAA,UACH,SAAS;AAAA,UACT;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,aAAS,eAAe,YAA0C;AAChE,qBAAI,MAAM,yBAAyB,UAAU,IAAI,MAAM;AACvD,cAAQ,QAAQ,WAAW,KAAK,GAAG,UAAU;AAC7C,aAAO,EAAE,GAAG,aAAa,SAAS;AAAA,IACpC;AAEA,aAAS,SAAS,MAAgC;AAChD,qBAAI,MAAM,mBAAmB,IAAI,IAAI,MAAM;AAC3C,cAAQ,QAAQ,OAAO;AACvB,aAAO;AAAA,IACT;AAEA,aAAS,UAAU,KAAa,QAAQ,IAAsB;AAC5D,qBAAI,MAAM,oBAAoB,GAAG,IAAI,KAAK,IAAI,MAAM;AACpD,cAAQ,QAAQ,OAAO,GAAG,IAAI;AAC9B,aAAO;AAAA,IACT;AAEA,aAAS,eAAe,KAAa,QAAQ,IAAsB;AACjE,qBAAI,MAAM,yBAAyB,GAAG,IAAI,KAAK,IAAI,MAAM;AACzD,cAAQ,QAAQ,YAAY,GAAG,IAAI;AACnC,aAAO;AAAA,IACT;AAEA,aAAS,UAAU,OAAc;AAC/B,cAAQ,QAAQ;AAChB,aAAO;AAAA,QACL,GAAG;AAAA,QACH;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,oBAAoB,MAAM,+CAA8B;AAAA,MACxD,WAAW,MAAM,+BAAsB;AAAA,MACvC,WAAW,MAAM,+BAAsB;AAAA,MACvC,WAAW,MAAM,+BAAsB;AAAA,IACzC;AAAA,EACF;AACF;",
|
|
6
|
+
"names": ["a", "import_kubernetes_fluent_client", "import_kubernetes_fluent_client", "import_ramda", "import_ramda", "promClient", "kind", "jsonPatch", "import_ramda", "import_kubernetes_fluent_client", "import_ramda", "express", "fs", "https", "namespace", "import_kubernetes_fluent_client", "import_types", "import_ramda", "kind"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"engines": {
|
|
10
10
|
"node": ">=18.0.0"
|
|
11
11
|
},
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.14.1",
|
|
13
13
|
"main": "dist/lib.js",
|
|
14
14
|
"types": "dist/lib.d.ts",
|
|
15
15
|
"scripts": {
|
|
@@ -27,41 +27,39 @@
|
|
|
27
27
|
"format:fix": "eslint src --fix && prettier src --write"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@kubernetes/client-node": "0.19.0",
|
|
31
30
|
"express": "4.18.2",
|
|
32
31
|
"fast-json-patch": "3.1.1",
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"pino": "
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"ramda": "0.29.0"
|
|
32
|
+
"kubernetes-fluent-client": "1.6.0",
|
|
33
|
+
"pino": "8.16.0",
|
|
34
|
+
"pino-pretty": "10.2.3",
|
|
35
|
+
"prom-client": "15.0.0",
|
|
36
|
+
"ramda": "0.29.1"
|
|
39
37
|
},
|
|
40
38
|
"devDependencies": {
|
|
39
|
+
"@commitlint/cli": "17.7.2",
|
|
40
|
+
"@commitlint/config-conventional": "17.7.0",
|
|
41
41
|
"@jest/globals": "29.7.0",
|
|
42
|
-
"@types/eslint": "8.44.
|
|
43
|
-
"@types/express": "4.17.
|
|
42
|
+
"@types/eslint": "8.44.4",
|
|
43
|
+
"@types/express": "4.17.19",
|
|
44
44
|
"@types/node": "18.x.x",
|
|
45
|
-
"@types/node-
|
|
46
|
-
"@types/
|
|
47
|
-
"@types/
|
|
48
|
-
"@types/
|
|
49
|
-
"@types/ramda": "0.29.4",
|
|
50
|
-
"@types/uuid": "9.0.4",
|
|
45
|
+
"@types/node-forge": "1.3.7",
|
|
46
|
+
"@types/prompts": "2.4.6",
|
|
47
|
+
"@types/ramda": "0.29.6",
|
|
48
|
+
"@types/uuid": "9.0.5",
|
|
51
49
|
"jest": "29.7.0",
|
|
52
|
-
"nock": "13.3.
|
|
50
|
+
"nock": "13.3.4",
|
|
53
51
|
"ts-jest": "29.1.1"
|
|
54
52
|
},
|
|
55
53
|
"peerDependencies": {
|
|
56
|
-
"@typescript-eslint/eslint-plugin": "6.
|
|
57
|
-
"@typescript-eslint/parser": "6.
|
|
54
|
+
"@typescript-eslint/eslint-plugin": "6.7.3",
|
|
55
|
+
"@typescript-eslint/parser": "6.7.3",
|
|
58
56
|
"commander": "11.0.0",
|
|
59
|
-
"esbuild": "0.19.
|
|
60
|
-
"eslint": "8.
|
|
57
|
+
"esbuild": "0.19.4",
|
|
58
|
+
"eslint": "8.50.0",
|
|
61
59
|
"node-forge": "1.3.1",
|
|
62
60
|
"prettier": "3.0.3",
|
|
63
61
|
"prompts": "2.4.2",
|
|
64
62
|
"typescript": "5.2.2",
|
|
65
|
-
"uuid": "9.0.
|
|
63
|
+
"uuid": "9.0.1"
|
|
66
64
|
}
|
|
67
65
|
}
|