Repository: kubernetes-sigs/security-profiles-operator
Pull request #980 (2022-06-06 23:08:45)

build(deps): bump github.com/stretchr/testify from 1.7.1 to 1.7.2
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.1 to 1.7.2.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/stretchr/testify/commit/41453c009af9a942261b7a25a88521d0d6804e7f"><code>41453c0</code></a> Update gopkg.in/yaml.v3</li>
<li><a href="https://github.com/stretchr/testify/commit/285adcc5ced0bb267a7c874cfa3ca238266ce14f"><code>285adcc</code></a> Update go versions in build matrix</li>
<li><a href="https://github.com/stretchr/testify/commit/6e7fab43fc3294f4e7c079e260746edcf8d66639"><code>6e7fab4</code></a> Bump actions/setup-go from 2 to 3.1.0</li>
<li><a href="https://github.com/stretchr/testify/commit/106ec21d14df07d4c33ec1155328800300c28c7f"><code>106ec21</code></a> use RWMutex</li>
<li><a href="https://github.com/stretchr/testify/commit/a409ccf19e17d8a90156521ce71c5e8ef8f6bca8"><code>a409ccf</code></a> fix data race in the suit</li>
<li><a href="https://github.com/stretchr/testify/commit/35864782d21250c3ff66874e87e5fdc9c79e0be1"><code>3586478</code></a> assert: fix typo</li>
<li><a href="https://github.com/stretchr/testify/commit/77977386932ab1866a4b9556a7af1ae347531786"><code>7797738</code></a> Update versions supported to include <code>go 1.16</code></li>
<li>See full diff in <a href="https://github.com/stretchr/testify/compare/v1.7.1...v1.7.2">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/stretchr/testify&package-manager=go_modules&previous-version=1.7.1&new-version=1.7.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

k8s-ci-robot: Hi @dependabot[bot]. Thanks for your PR.

I'm waiting for a [kubernetes-sigs](https://github.com/orgs/kubernetes-sigs/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://git.k8s.io/community/community-membership.md#member) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>

k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/980#" title="Author self-approved">dependabot[bot]</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **jhrozek** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @jhrozek` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes-sigs/security-profiles-operator/blob/main/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["jhrozek"]} -->
k8s-ci-robot: @dependabot[bot]: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-security-profiles-operator-test-e2e | d4ec4bbdfcfdcbf713cb53c50579bb5b12ae30a8 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/980/pull-security-profiles-operator-test-e2e/1533949048615079936) | true | `/test pull-security-profiles-operator-test-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=980). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Adependabot[bot]). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
saschagrunert: /retest
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/980#" title="Author self-approved">dependabot[bot]</a>*, *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/980#pullrequestreview-997646588" title="Approved">saschagrunert</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/security-profiles-operator/blob/main/OWNERS)~~ [saschagrunert]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/api/profilebinding/v1alpha1/profilebinding_types.go b/api/profilebinding/v1alpha1/profilebinding_types.go
index 8f92cddab..a4036baed 100644
--- a/api/profilebinding/v1alpha1/profilebinding_types.go
+++ b/api/profilebinding/v1alpha1/profilebinding_types.go
@@ -39,7 +39,7 @@ type ProfileBindingSpec struct {
 type ProfileRef struct {
 	// Kind of object to be bound.
 	// +kubebuilder:validation:Enum=SeccompProfile;SelinuxProfile
-	Kind ProfileBindingKind `json:"kind"` // TODO(cmurphy) add SelinuxProfile
+	Kind ProfileBindingKind `json:"kind"`
 	// Name of the profile within the current namespace to which to bind the selected pods.
 	Name string `json:"name"`
 }
diff --git a/go.mod b/go.mod
index f198a65d2..551bb66fb 100644
--- a/go.mod
+++ b/go.mod
@@ -15,11 +15,11 @@ require (
 	github.com/nxadm/tail v1.4.8
 	github.com/openshift/api v0.0.0-20220209124712-b632c5fc10c0
 	github.com/pjbgf/go-apparmor v0.0.7
-	github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.56.3
+	github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.57.0
 	github.com/prometheus/client_golang v1.12.2
 	github.com/prometheus/client_model v0.2.0
 	github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921
-	github.com/stretchr/testify v1.7.1
+	github.com/stretchr/testify v1.7.2
 	github.com/urfave/cli/v2 v2.8.1
 	golang.org/x/net v0.0.0-20220225172249-27dd8689420f
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
@@ -121,7 +121,7 @@ require (
 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
 	gopkg.in/warnings.v0 v0.1.2 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
-	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
 	k8s.io/apiextensions-apiserver v0.24.0 // indirect
 	k8s.io/component-base v0.24.0 // indirect
 	k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
diff --git a/go.sum b/go.sum
index 16dd3e999..0e8eedfb4 100644
--- a/go.sum
+++ b/go.sum
@@ -896,8 +896,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
 github.com/proglottis/gpgme v0.1.1/go.mod h1:fPbW/EZ0LvwQtH8Hy7eixhp1eF3G39dtx7GUN+0Gmy0=
-github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.56.3 h1:IXkP/3HjFBy6mHr0c9G3SLo3MWgbkd6zrvDpt+c057o=
-github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.56.3/go.mod h1:/xf16Bu3krDP6G5WhrJL9avDnLW/AN0g7hAIK63mbes=
+github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.57.0 h1:dslXhV7NbAFID2fh0ZLMjodbMYuitiJzDEpYNOoyRrg=
+github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.57.0/go.mod h1:tflNO6iwG09icVcOe2VfhC73fmtKSKT1aNXYnVtAumU=
 github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
@@ -1022,8 +1022,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/sylabs/sif/v2 v2.7.0/go.mod h1:TiyBWsgWeh5yBeQFNuQnvROwswqK7YJT8JA1L53bsXQ=
 github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@@ -1701,8 +1702,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
 gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
 gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
diff --git a/installation-usage.md b/installation-usage.md
index cf238d931..5fca34857 100644
--- a/installation-usage.md
+++ b/installation-usage.md
@@ -10,14 +10,17 @@
 - [Set logging verbosity](#set-logging-verbosity)
 - [Configure the SELinux type](#configure-the-selinux-type)
 - [Restrict the allowed syscalls in seccomp profiles](#restrict-the-allowed-syscalls-in-seccomp-profiles)
-- [Create Profile](#create-profile)
-  - [Apply profile to pod](#apply-profile-to-pod)
+- [Create a seccomp profile](#create-a-seccomp-profile)
+  - [Apply a seccomp profile to a pod](#apply-a-seccomp-profile-to-a-pod)
   - [Base syscalls for a container runtime](#base-syscalls-for-a-container-runtime)
   - [Bind workloads to profiles with ProfileBindings](#bind-workloads-to-profiles-with-profilebindings)
   - [Record profiles from workloads with <code>ProfileRecordings</code>](#record-profiles-from-workloads-with-profilerecordings)
     - [Hook based recording](#hook-based-recording)
     - [Log enricher based recording](#log-enricher-based-recording)
     - [eBPF based recording](#ebpf-based-recording)
+- [Create a SELinux Profile](#create-a-selinux-profile)
+  - [Apply a SELinux profile to a pod](#apply-a-selinux-profile-to-a-pod)
+  - [Record a SELinux profile](#record-a-selinux-profile)
 - [Restricting to a Single Namespace](#restricting-to-a-single-namespace)
 - [Using metrics](#using-metrics)
   - [Available metrics](#available-metrics)
@@ -27,6 +30,9 @@
 - [Troubleshooting](#troubleshooting)
   - [Enable CPU and memory profiling](#enable-cpu-and-memory-profiling)
   - [Use a custom <code>/proc</code> location for nested environments like <code>kind</code>](#use-a-custom-proc-location-for-nested-environments-like-kind)
+- [Notes on OpenShift and SCCs](#notes-on-openshift-and-sccs)
+  - [SELinux recording should allow <code>seLinuxContext: RunAsAny</code>](#selinux-recording-should-allow-selinuxcontext-runasany)
+  - [Replicating controllers and SCCs](#replicating-controllers-and-sccs)
 - [Uninstalling](#uninstalling)
 <!-- /toc -->
 
@@ -172,7 +178,7 @@ into the allowed list. All profiles not complying with this rule, it will be rej
 Also every time when the list of allowed syscalls is modified in the spod configuration, the operator will
 automatically identify the already installed profiles which are not compliant and remove them.
 
-## Create Profile
+## Create a seccomp profile
 
 Use the `SeccompProfile` kind to create profiles. Example:
 
@@ -195,7 +201,7 @@ run it without root G/UID. This will be done by creating a symlink from the
 rootless profile storage `/var/lib/security-profiles-operator` to the default seccomp root
 path inside of the kubelet root `/var/lib/kubelet/seccomp/operator`.
 
-### Apply profile to pod
+### Apply a seccomp profile to a pod
 
 Create a pod using one of the created profiles. On Kubernetes >= 1.19, the
 profile can be specified as part of the pod's security context:
@@ -295,8 +301,7 @@ with version 0.20.1).
 
 If you do not want to directly modify the SecurityContext of a Pod, for instance
 if you are deploying a public application, you can use the ProfileBinding
-resource to bind a security profile to a container's securityContext. Currently,
-the ProfileBinding resource can only refer to a SeccompProfile.
+resource to bind a security profile to a container's securityContext.
 
 To bind a Pod that uses an 'nginx:1.19.1' image to the 'profile-complain'
 example seccomp profile, create a ProfileBinding in the same namespace as both
@@ -324,13 +329,18 @@ $ kubectl get pod test-pod -o jsonpath='{.spec.containers[*].securityContext.sec
 {"localhostProfile":"operator/default/generic/profile-complain-unsafe.json","type":"Localhost"}
 ```
 
+Binding a SELinux profile works in the same way, except you'd use the `SelinuxProfile` kind.
+`RawSelinuxProfiles` are currently not supported.
+
 ### Record profiles from workloads with `ProfileRecordings`
 
-The operator is capable of recording seccomp profiles by the usage of the
+The operator is capable of recording seccomp or SELinux profiles by the usage of the
 built-in [eBPF](https://ebpf.io) recorder, [oci-seccomp-bpf-hook][bpf-hook] or
 by evaluating the [audit][auditd] or [syslog][syslog] files. Each method has
 its pros and cons as well as separate technical requirements.
 
+Note that SELinux profiles can only be recorded using the log enricher.
+
 #### Hook based recording
 
 [OCI hooks][hooks] are part of the OCI runtime-spec, which allow to hook into
@@ -525,7 +535,7 @@ workload via a BPF module.
 
 #### Log enricher based recording
 
-When using the log enricher for recording seccomp profiles, please ensure that
+When using the log enricher for recording seccomp or SELinux profiles, please ensure that
 the feature [is enabled within the spod](#using-the-log-enricher) configuration
 resource. The log based recording works in the same way with
 [containerd][containerd] and [CRI-O][cri-o], while using the node local logs as
@@ -596,6 +606,9 @@ test-recording-nginx   Installed   15s
 test-recording-redis   Installed   15s
 ```
 
+Recording a SELinux profile would work the same, except you'd use `kind: SelinuxProfile`
+in the `ProfileRecording` object.
+
 #### eBPF based recording
 
 The operator also supports an [eBPF](https://ebpf.io) based recorder. This
@@ -713,6 +726,106 @@ NAME                 STATUS      AGE
 my-recording-nginx   Installed   15s
 ```
 
+## Create a SELinux Profile
+
+There are two kinds that can be used to define a SELinux profile - `SelinuxProfile` and `RawSelinuxProfile`.
+
+The default one and the one created during workload recording is `SelinuxProfile`. It is more readable
+and has several features that allow for better security hardening and better readability. The `RawSelinuxProfile`
+kind should be used mostly when there's an already existing SELinux policy (perhaps created with udica)
+that you wish to use in your cluster.
+
+In particular, the `SelinuxProfile` kind:
+- restricts the profiles to inherit from to the current namespace or a system-wide profile. Because there
+  are typically many profiles installed on the system, but only a subset should be used by cluster workloads,
+  the inheritable system profiles are listed in the `spod` instance in `spec.selinuxOptions.allowedSystemProfiles`.
+  Depending on what distribution your nodes run, the base profile might vary, on RHEL-based systems, you might
+  want to look at what profiles are shipped in the `container-selinux` RPM package.
+- performs basic validation of the permissions, classes and labels
+- adds a new keyword `@self` that describes the process using the policy. This allows to reuse a policy between
+  workloads and namespaces easily, as the "usage" of the policy (see below) is based on the name and namespace.
+
+Below is an example of a policy that can be used with a non-privileged nginx workload:
+```yaml
+apiVersion: security-profiles-operator.x-k8s.io/v1alpha2
+kind: SelinuxProfile
+metadata:
+  name: nginx-secure
+  namespace: nginx-deploy
+spec:
+  allow:
+    '@self':
+      tcp_socket:
+      - listen
+    http_cache_port_t:
+      tcp_socket:
+      - name_bind
+    node_t:
+      tcp_socket:
+      - node_bind
+  inherit:
+  - kind: System
+    name: container
+```
+
+After the policy is created, we can wait for selinuxd to install it:
+```bash
+$ kubectl wait --for=condition=ready selinuxprofile nginx-secure
+selinuxprofile.security-profiles-operator.x-k8s.io/nginx-secure condition met
+```
+
+The CIL-formatted policies are placed into an `emptyDir` owned by the SPO where you can view
+the resulting CIL policy:
+```shell
+$ kubectl exec -it -c selinuxd spod-fm55x -- sh
+sh-4.4# cat /etc/selinux.d/nginx-secure_nginx-deploy.cil
+(block nginx-secure_nginx-deploy
+(blockinherit container)
+(allow process nginx-secure_nginx-deploy.process ( tcp_socket ( listen )))
+(allow process http_cache_port_t ( tcp_socket ( name_bind )))
+(allow process node_t ( tcp_socket ( node_bind )))
+)
+```
+
+However, the binary policies are installed into the system policy store on the nodes, so you can verify
+that a policy has been installed:
+```shell
+# semodule -l | grep nginx-secure
+```
+
+### Apply a SELinux profile to a pod
+
+SELinux profiles are referenced to based on their "usage" string:
+```shell
+kubectl get selinuxprofile.security-profiles-operator.x-k8s.io/nginx-secure -nnginx-deploy -ojsonpath='{.status.usage}'
+nginx-secure_nginx-deploy.process%
+```
+
+Use this string in the workload manifest in the `.spec.containers[].securityContext.seLinuxOptions` attribute:
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+  name: nginx-secure
+  namespace: nginx-deploy
+spec:
+  containers:
+    - image: nginxinc/nginx-unprivileged:1.21
+      name: nginx
+      securityContext:
+        seLinuxOptions:
+          # NOTE: This uses an appropriate SELinux type
+          type: nginx-secure_nginx-deploy.process
+```
+
+Note that the SELinux type must exist before creating the workload.
+
+### Record a SELinux profile
+
+Please refer to the seccomp recording documentation, recording a SELinux
+profile would work the same, except you'd use `kind: SelinuxProfile`. Note
+that only the log enricher is capable of recording SELinux profiles.
+
 ## Restricting to a Single Namespace
 
 The security-profiles-operator can optionally be run to watch SeccompProfiles in
@@ -1142,6 +1255,134 @@ bpf-recorder. To use a custom path for `/proc`, just patch the spod accordingly:
 kubectl patch spod spod --type=merge -p '{"spec":{"hostProcVolumePath":"/my-proc"}}'
 ```
 
+## Notes on OpenShift and SCCs
+
+There are several things particular to OpenShift that are useful to be aware of when
+deploying and recording security profiles, mostly coming from OpenShift's default use
+of SCCs.
+
+### SELinux recording should allow `seLinuxContext: RunAsAny`
+
+Recording of SELinux policies is implemented with a webhook that injects a special SELinux
+type to the pods being recorded. This type makes the pod run in "permissive" mode, logging
+all the AVC denials into `audit.log`. By default, especially with the more restrictive SCCs,
+a workload is not allowed to run with a custom SELinux policy, but uses an autogenerated type.
+
+Therefore in order to record a workload, the workload must use a service account that is allowed
+to use an SCC that allows the webhook to inject this permissive type into it. This can be achieved
+by using any SCC that uses `seLinuxContext: RunAsAny`, including the `privileged` SCC shipped
+by default with OpenShift.
+
+### Replicating controllers and SCCs
+
+When deploying security policies (both SELinux and seccomp) for replicating controllers (deployments,
+daemonsets, ...), note that the pods that these controllers spawn are not running with the identity
+of the user who creates the workload. Unless a `ServiceAccount` is selected, this means that the pods
+might fall back to using one of the secure but restricted SCCs which don't allow to use a custom security
+policy.
+
+One option is to use an SCC with `seLinuxContext: RunAsAny` and/or `seccompProfiles: [*]`, but it's
+more secure to only restrict your workloads to the security profiles they should be using.
+
+Taking the SELinux policy we recorded earlier for an nginx deployment as an
+example, we might create the following SCC which is based on the `restricted`
+SCC shipped in OpenShift, just allows our SELinux policy to be used.
+Note that we'll be deploying in the `nginx-secure` namespace, as you can
+see from the ServiceAccount name we are putting into the `users` array.
+```yaml
+apiVersion: security.openshift.io/v1
+kind: SecurityContextConstraints
+metadata:
+  annotations:
+    kubernetes.io/description: A special SCC for running nginx with a custom SELinux policy
+  name: nginx-secure
+allowHostIPC: false
+allowHostNetwork: false
+allowHostPID: false
+allowHostPorts: false
+allowPrivilegeEscalation: true
+allowPrivilegedContainer: false
+allowedCapabilities: null
+defaultAddCapabilities: null
+fsGroup:
+  type: MustRunAs
+priority: null
+readOnlyRootFilesystem: false
+requiredDropCapabilities:
+- KILL
+- MKNOD
+- SETUID
+- SETGID
+runAsUser:
+  type: MustRunAsRange
+seLinuxContext:
+  type: MustRunAs
+  seLinuxOptions:
+    type: test-selinux-recording-nginx-0_nginx-secure.process
+supplementalGroups:
+  type: RunAsAny
+users:
+- system:serviceaccount:nginx-secure:nginx-sa
+volumes:
+- configMap
+- downwardAPI
+- emptyDir
+- persistentVolumeClaim
+- projected
+- secret
+```
+
+Please note that a common mistake when creating custom SCCs is to bind them to a wide range of users or SAs
+through the `group` attribute, e.g. the `system:authenticated` group. Make sure your SCC is only usable by
+the serviceAccount it is supposed to be used by. Please refer to the [OCP documentation](https://docs.openshift.com/container-platform/4.9/authentication/managing-security-context-constraints.html)
+or [this Red Hat blog post](https://cloud.redhat.com/blog/managing-sccs-in-openshift) for more information
+on managing SCCs.
+
+Then we create the appropriate role:
+```yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: nginx
+  namespace: nginx-secure
+rules:
+- apiGroups:
+  - security.openshift.io
+  resources:
+  - securitycontextconstraints
+  resourceNames:
+  - nginx-secure
+  verbs:
+  - use
+```
+and finally a role binding and the SA.
+
+With all that set up, we can finally create our deployment:
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: my-deployment
+spec:
+  selector:
+    matchLabels:
+      app: nginx
+  replicas: 2
+  template:
+    metadata:
+      labels:
+        app: nginx
+    spec:
+      serviceAccountName: nginx-sa
+      containers:
+      - name: nginx
+        image: nginxinc/nginx-unprivileged:1.21
+```
+
+Note that we don't specify the SELinux type at all in the workload, that's handled by the SCC instead.
+When the pods are created through the deployment and its `ReplicaSet`, they should be
+running with the appropriate profile.
+
 ## Uninstalling
 
 To uninstall, remove the profiles before removing the rest of the operator:
diff --git a/vendor/github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1/thanos_types.go b/vendor/github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1/thanos_types.go
index 23f60ed0c..aff25c0b7 100644
--- a/vendor/github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1/thanos_types.go
+++ b/vendor/github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1/thanos_types.go
@@ -151,10 +151,12 @@ type ThanosRulerSpec struct {
 	// This defaults to web
 	PortName string `json:"portName,omitempty"`
 	// Interval between consecutive evaluations.
-	EvaluationInterval string `json:"evaluationInterval,omitempty"`
+	// +kubebuilder:default:="15s"
+	EvaluationInterval Duration `json:"evaluationInterval,omitempty"`
 	// Time duration ThanosRuler shall retain data for. Default is '24h',
 	// and must match the regular expression `[0-9]+(ms|s|m|h|d|w|y)` (milliseconds seconds minutes hours days weeks years).
-	Retention string `json:"retention,omitempty"`
+	// +kubebuilder:default:="24h"
+	Retention Duration `json:"retention,omitempty"`
 	// Containers allows injecting additional containers or modifying operator generated
 	// containers. This can be used to allow adding an authentication proxy to a ThanosRuler pod or
 	// to change the behavior of an operator generated container. Containers described here modify
@@ -208,6 +210,10 @@ type ThanosRulerSpec struct {
 	// AlertRelabelConfigFile specifies the path of the alert relabeling configuration file.
 	// When used alongside with AlertRelabelConfigs, alertRelabelConfigFile takes precedence.
 	AlertRelabelConfigFile *string `json:"alertRelabelConfigFile,omitempty"`
+	// Pods' hostAliases configuration
+	// +listType=map
+	// +listMapKey=ip
+	HostAliases []HostAlias `json:"hostAliases,omitempty"`
 }
 
 // ThanosRulerStatus is the most recent observed status of the ThanosRuler. Read-only. Not
diff --git a/vendor/github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1/types.go b/vendor/github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1/types.go
index 6522ffcd1..3401a8817 100644
--- a/vendor/github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1/types.go
+++ b/vendor/github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1/types.go
@@ -337,6 +337,10 @@ type CommonPrometheusFields struct {
 	// This is an alpha field and requires enabling StatefulSetMinReadySeconds feature gate.
 	// +optional
 	MinReadySeconds *uint32 `json:"minReadySeconds,omitempty"`
+	// Pods' hostAliases configuration
+	// +listType=map
+	// +listMapKey=ip
+	HostAliases []HostAlias `json:"hostAliases,omitempty"`
 }
 
 // Prometheus defines a Prometheus deployment.
@@ -380,6 +384,17 @@ type ByteSize string
 // +kubebuilder:validation:Pattern:="^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$"
 type Duration string
 
+// HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the
+// pod's hosts file.
+type HostAlias struct {
+	// IP address of the host file entry.
+	// +kubebuilder:validation:Required
+	IP string `json:"ip"`
+	// Hostnames for the above IP address.
+	// +kubebuilder:validation:Required
+	Hostnames []string `json:"hostnames"`
+}
+
 // PrometheusSpec is a specification of the desired behavior of the Prometheus cluster. More info:
 // https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
 // +k8s:openapi-gen=true
@@ -565,13 +580,13 @@ type PrometheusStatus struct {
 	// Total number of unavailable pods targeted by this Prometheus deployment.
 	UnavailableReplicas int32 `json:"unavailableReplicas"`
 	// The current state of the Prometheus deployment.
-	// +patchMergeKey=type
-	// +patchMergeStrategy=merge
+	// +listType=map
+	// +listMapKey=type
 	// +optional
 	Conditions []PrometheusCondition `json:"conditions,omitempty"`
 	// The list has one entry per shard. Each entry provides a summary of the shard status.
-	// +patchMergeKey=shardID
-	// +patchMergeStrategy=merge
+	// +listType=map
+	// +listMapKey=shardID
 	// +optional
 	ShardStatuses []ShardStatus `json:"shardStatuses,omitempty"`
 }
@@ -1189,6 +1204,14 @@ type PodMonitorSpec struct {
 	// Per-scrape limit on length of labels value that will be accepted for a sample.
 	// Only valid in Prometheus versions 2.27.0 and newer.
 	LabelValueLengthLimit uint64 `json:"labelValueLengthLimit,omitempty"`
+	// Attaches node metadata to discovered targets. Only valid for role: pod.
+	// Only valid in Prometheus versions 2.35.0 and newer.
+	AttachMetadata *AttachMetadata `json:"attachMetadata,omitempty"`
+}
+
+type AttachMetadata struct {
+	// When set to true, Prometheus must have permissions to get Nodes.
+	Node bool `json:"node,omitempty"`
 }
 
 // PodMetricsEndpoint defines a scrapeable endpoint of a Kubernetes Pod serving Prometheus metrics.
@@ -1836,6 +1859,10 @@ type AlertmanagerSpec struct {
 	// This is an alpha field and requires enabling StatefulSetMinReadySeconds feature gate.
 	// +optional
 	MinReadySeconds *uint32 `json:"minReadySeconds,omitempty"`
+	// Pods' hostAliases configuration
+	// +listType=map
+	// +listMapKey=ip
+	HostAliases []HostAlias `json:"hostAliases,omitempty"`
 	// EXPERIMENTAL: alertmanagerConfiguration specifies the global Alertmanager configuration.
 	// If defined, it takes precedence over the `configSecret` field.
 	// This field may change in future releases.
diff --git a/vendor/github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1/zz_generated.deepcopy.go b/vendor/github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1/zz_generated.deepcopy.go
index b4f77c393..1f926351d 100644
--- a/vendor/github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1/zz_generated.deepcopy.go
+++ b/vendor/github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1/zz_generated.deepcopy.go
@@ -288,6 +288,13 @@ func (in *AlertmanagerSpec) DeepCopyInto(out *AlertmanagerSpec) {
 		*out = new(uint32)
 		**out = **in
 	}
+	if in.HostAliases != nil {
+		in, out := &in.HostAliases, &out.HostAliases
+		*out = make([]HostAlias, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
 	if in.AlertmanagerConfiguration != nil {
 		in, out := &in.AlertmanagerConfiguration, &out.AlertmanagerConfiguration
 		*out = new(AlertmanagerConfiguration)
@@ -335,6 +342,21 @@ func (in *ArbitraryFSAccessThroughSMsConfig) DeepCopy() *ArbitraryFSAccessThroug
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AttachMetadata) DeepCopyInto(out *AttachMetadata) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AttachMetadata.
+func (in *AttachMetadata) DeepCopy() *AttachMetadata {
+	if in == nil {
+		return nil
+	}
+	out := new(AttachMetadata)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Authorization) DeepCopyInto(out *Authorization) {
 	*out = *in
@@ -591,6 +613,13 @@ func (in *CommonPrometheusFields) DeepCopyInto(out *CommonPrometheusFields) {
 		*out = new(uint32)
 		**out = **in
 	}
+	if in.HostAliases != nil {
+		in, out := &in.HostAliases, &out.HostAliases
+		*out = make([]HostAlias, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonPrometheusFields.
@@ -744,6 +773,26 @@ func (in *Endpoint) DeepCopy() *Endpoint {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *HostAlias) DeepCopyInto(out *HostAlias) {
+	*out = *in
+	if in.Hostnames != nil {
+		in, out := &in.Hostnames, &out.Hostnames
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostAlias.
+func (in *HostAlias) DeepCopy() *HostAlias {
+	if in == nil {
+		return nil
+	}
+	out := new(HostAlias)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *MetadataConfig) DeepCopyInto(out *MetadataConfig) {
 	*out = *in
@@ -1010,6 +1059,11 @@ func (in *PodMonitorSpec) DeepCopyInto(out *PodMonitorSpec) {
 	}
 	in.Selector.DeepCopyInto(&out.Selector)
 	in.NamespaceSelector.DeepCopyInto(&out.NamespaceSelector)
+	if in.AttachMetadata != nil {
+		in, out := &in.AttachMetadata, &out.AttachMetadata
+		*out = new(AttachMetadata)
+		**out = **in
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodMonitorSpec.
@@ -2245,6 +2299,13 @@ func (in *ThanosRulerSpec) DeepCopyInto(out *ThanosRulerSpec) {
 		*out = new(string)
 		**out = **in
 	}
+	if in.HostAliases != nil {
+		in, out := &in.HostAliases, &out.HostAliases
+		*out = make([]HostAlias, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ThanosRulerSpec.
diff --git a/vendor/gopkg.in/yaml.v3/decode.go b/vendor/gopkg.in/yaml.v3/decode.go
index df36e3a30..0173b6982 100644
--- a/vendor/gopkg.in/yaml.v3/decode.go
+++ b/vendor/gopkg.in/yaml.v3/decode.go
@@ -100,7 +100,10 @@ func (p *parser) peek() yaml_event_type_t {
 	if p.event.typ != yaml_NO_EVENT {
 		return p.event.typ
 	}
-	if !yaml_parser_parse(&p.parser, &p.event) {
+	// It's curious choice from the underlying API to generally return a
+	// positive result on success, but on this case return true in an error
+	// scenario. This was the source of bugs in the past (issue #666).
+	if !yaml_parser_parse(&p.parser, &p.event) || p.parser.error != yaml_NO_ERROR {
 		p.fail()
 	}
 	return p.event.typ
@@ -320,6 +323,8 @@ type decoder struct {
 	decodeCount int
 	aliasCount  int
 	aliasDepth  int
+
+	mergedFields map[interface{}]bool
 }
 
 var (
@@ -808,6 +813,11 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
 		}
 	}
 
+	mergedFields := d.mergedFields
+	d.mergedFields = nil
+
+	var mergeNode *Node
+
 	mapIsNew := false
 	if out.IsNil() {
 		out.Set(reflect.MakeMap(outt))
@@ -815,11 +825,18 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
 	}
 	for i := 0; i < l; i += 2 {
 		if isMerge(n.Content[i]) {
-			d.merge(n.Content[i+1], out)
+			mergeNode = n.Content[i+1]
 			continue
 		}
 		k := reflect.New(kt).Elem()
 		if d.unmarshal(n.Content[i], k) {
+			if mergedFields != nil {
+				ki := k.Interface()
+				if mergedFields[ki] {
+					continue
+				}
+				mergedFields[ki] = true
+			}
 			kkind := k.Kind()
 			if kkind == reflect.Interface {
 				kkind = k.Elem().Kind()
@@ -833,6 +850,12 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
 			}
 		}
 	}
+
+	d.mergedFields = mergedFields
+	if mergeNode != nil {
+		d.merge(n, mergeNode, out)
+	}
+
 	d.stringMapType = stringMapType
 	d.generalMapType = generalMapType
 	return true
@@ -844,7 +867,8 @@ func isStringMap(n *Node) bool {
 	}
 	l := len(n.Content)
 	for i := 0; i < l; i += 2 {
-		if n.Content[i].ShortTag() != strTag {
+		shortTag := n.Content[i].ShortTag()
+		if shortTag != strTag && shortTag != mergeTag {
 			return false
 		}
 	}
@@ -861,7 +885,6 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
 	var elemType reflect.Type
 	if sinfo.InlineMap != -1 {
 		inlineMap = out.Field(sinfo.InlineMap)
-		inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
 		elemType = inlineMap.Type().Elem()
 	}
 
@@ -870,6 +893,9 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
 		d.prepare(n, field)
 	}
 
+	mergedFields := d.mergedFields
+	d.mergedFields = nil
+	var mergeNode *Node
 	var doneFields []bool
 	if d.uniqueKeys {
 		doneFields = make([]bool, len(sinfo.FieldsList))
@@ -879,13 +905,20 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
 	for i := 0; i < l; i += 2 {
 		ni := n.Content[i]
 		if isMerge(ni) {
-			d.merge(n.Content[i+1], out)
+			mergeNode = n.Content[i+1]
 			continue
 		}
 		if !d.unmarshal(ni, name) {
 			continue
 		}
-		if info, ok := sinfo.FieldsMap[name.String()]; ok {
+		sname := name.String()
+		if mergedFields != nil {
+			if mergedFields[sname] {
+				continue
+			}
+			mergedFields[sname] = true
+		}
+		if info, ok := sinfo.FieldsMap[sname]; ok {
 			if d.uniqueKeys {
 				if doneFields[info.Id] {
 					d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))
@@ -911,6 +944,11 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
 			d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
 		}
 	}
+
+	d.mergedFields = mergedFields
+	if mergeNode != nil {
+		d.merge(n, mergeNode, out)
+	}
 	return true
 }
 
@@ -918,19 +956,29 @@ func failWantMap() {
 	failf("map merge requires map or sequence of maps as the value")
 }
 
-func (d *decoder) merge(n *Node, out reflect.Value) {
-	switch n.Kind {
+func (d *decoder) merge(parent *Node, merge *Node, out reflect.Value) {
+	mergedFields := d.mergedFields
+	if mergedFields == nil {
+		d.mergedFields = make(map[interface{}]bool)
+		for i := 0; i < len(parent.Content); i += 2 {
+			k := reflect.New(ifaceType).Elem()
+			if d.unmarshal(parent.Content[i], k) {
+				d.mergedFields[k.Interface()] = true
+			}
+		}
+	}
+
+	switch merge.Kind {
 	case MappingNode:
-		d.unmarshal(n, out)
+		d.unmarshal(merge, out)
 	case AliasNode:
-		if n.Alias != nil && n.Alias.Kind != MappingNode {
+		if merge.Alias != nil && merge.Alias.Kind != MappingNode {
 			failWantMap()
 		}
-		d.unmarshal(n, out)
+		d.unmarshal(merge, out)
 	case SequenceNode:
-		// Step backwards as earlier nodes take precedence.
-		for i := len(n.Content) - 1; i >= 0; i-- {
-			ni := n.Content[i]
+		for i := 0; i < len(merge.Content); i++ {
+			ni := merge.Content[i]
 			if ni.Kind == AliasNode {
 				if ni.Alias != nil && ni.Alias.Kind != MappingNode {
 					failWantMap()
@@ -943,6 +991,8 @@ func (d *decoder) merge(n *Node, out reflect.Value) {
 	default:
 		failWantMap()
 	}
+
+	d.mergedFields = mergedFields
 }
 
 func isMerge(n *Node) bool {
diff --git a/vendor/gopkg.in/yaml.v3/parserc.go b/vendor/gopkg.in/yaml.v3/parserc.go
index ac66fccc0..268558a0d 100644
--- a/vendor/gopkg.in/yaml.v3/parserc.go
+++ b/vendor/gopkg.in/yaml.v3/parserc.go
@@ -687,6 +687,9 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i
 func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
 	if first {
 		token := peek_token(parser)
+		if token == nil {
+			return false
+		}
 		parser.marks = append(parser.marks, token.start_mark)
 		skip_token(parser)
 	}
@@ -786,7 +789,7 @@ func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) {
 	}
 
 	token := peek_token(parser)
-	if token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN {
+	if token == nil || token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN {
 		return
 	}
 
@@ -813,6 +816,9 @@ func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) {
 func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
 	if first {
 		token := peek_token(parser)
+		if token == nil {
+			return false
+		}
 		parser.marks = append(parser.marks, token.start_mark)
 		skip_token(parser)
 	}
@@ -922,6 +928,9 @@ func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_ev
 func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
 	if first {
 		token := peek_token(parser)
+		if token == nil {
+			return false
+		}
 		parser.marks = append(parser.marks, token.start_mark)
 		skip_token(parser)
 	}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index f1267ab04..3e498a0c7 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -357,7 +357,7 @@ github.com/pkg/errors
 # github.com/pmezard/go-difflib v1.0.0
 ## explicit
 github.com/pmezard/go-difflib/difflib
-# github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.56.3
+# github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.57.0
 ## explicit; go 1.17
 github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring
 github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1
@@ -402,7 +402,7 @@ github.com/spf13/cobra
 # github.com/spf13/pflag v1.0.5
 ## explicit; go 1.12
 github.com/spf13/pflag
-# github.com/stretchr/testify v1.7.1
+# github.com/stretchr/testify v1.7.2
 ## explicit; go 1.13
 github.com/stretchr/testify/assert
 github.com/stretchr/testify/require
@@ -627,7 +627,7 @@ gopkg.in/warnings.v0
 # gopkg.in/yaml.v2 v2.4.0
 ## explicit; go 1.15
 gopkg.in/yaml.v2
-# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
+# gopkg.in/yaml.v3 v3.0.1
 ## explicit
 gopkg.in/yaml.v3
 # k8s.io/api v0.24.1


Test patch:
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go b/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go
index df22c47fc..da867903e 100644
--- a/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go
+++ b/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go
@@ -9,7 +9,7 @@ package assert
 
 import "reflect"
 
-// Wrapper around reflect.Value.CanConvert, for compatability
+// Wrapper around reflect.Value.CanConvert, for compatibility
 // reasons.
 func canConvert(value reflect.Value, to reflect.Type) bool {
 	return value.CanConvert(to)
diff --git a/vendor/github.com/stretchr/testify/suite/suite.go b/vendor/github.com/stretchr/testify/suite/suite.go
index b9b5d1c56..1c402e8df 100644
--- a/vendor/github.com/stretchr/testify/suite/suite.go
+++ b/vendor/github.com/stretchr/testify/suite/suite.go
@@ -7,6 +7,7 @@ import (
 	"reflect"
 	"regexp"
 	"runtime/debug"
+	"sync"
 	"testing"
 	"time"
 
@@ -21,17 +22,22 @@ var matchMethod = flag.String("testify.m", "", "regular expression to select tes
 // retrieving the current *testing.T context.
 type Suite struct {
 	*assert.Assertions
+	mu      sync.RWMutex
 	require *require.Assertions
 	t       *testing.T
 }
 
 // T retrieves the current *testing.T context.
 func (suite *Suite) T() *testing.T {
+	suite.mu.RLock()
+	defer suite.mu.RUnlock()
 	return suite.t
 }
 
 // SetT sets the current *testing.T context.
 func (suite *Suite) SetT(t *testing.T) {
+	suite.mu.Lock()
+	defer suite.mu.Unlock()
 	suite.t = t
 	suite.Assertions = assert.New(t)
 	suite.require = require.New(t)
@@ -39,6 +45,8 @@ func (suite *Suite) SetT(t *testing.T) {
 
 // Require returns a require context for suite.
 func (suite *Suite) Require() *require.Assertions {
+	suite.mu.Lock()
+	defer suite.mu.Unlock()
 	if suite.require == nil {
 		suite.require = require.New(suite.T())
 	}
@@ -51,6 +59,8 @@ func (suite *Suite) Require() *require.Assertions {
 // assert.Assertions with require.Assertions), this method is provided so you
 // can call `suite.Assert().NoError()`.
 func (suite *Suite) Assert() *assert.Assertions {
+	suite.mu.Lock()
+	defer suite.mu.Unlock()
 	if suite.Assertions == nil {
 		suite.Assertions = assert.New(suite.T())
 	}