Repository: kubernetes/minikube
Pull request #14695 (2022-08-01 22:21:09)

Limit number of audit entries
Closes https://github.com/kubernetes/minikube/issues/14543

- Added feature to cap amount of audit entries
  - Once limit is passed, the oldest entries are trimmed
  - By default limits audit entries to 1,000 lines
- Added config option `MaxAuditEntries`
  - Allows to customize the max amount of audit entries to retain
  - `minikube config set MaxAuditEntries <number>`
  - Setting to `0` will set to unlimited audit entries
- Added test to ensure cap and `MaxAuditEntries` are working


Patch:
diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
index 1695db63b..3960f2621 100644
--- a/.github/workflows/master.yml
+++ b/.github/workflows/master.yml
@@ -395,7 +395,7 @@ jobs:
       JOB_NAME: "functional_virtualbox_macos"
       GOPOGH_RESULT: ""
       SHELL: "/bin/bash" # To prevent https://github.com/kubernetes/minikube/issues/6643
-    runs-on: macos-12
+    runs-on: macos-10.15
     steps:
       - name: Install kubectl
         shell: bash
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 38afb2d13..94fc5c0ca 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -395,7 +395,7 @@ jobs:
       JOB_NAME: "functional_virtualbox_macos"
       GOPOGH_RESULT: ""
       SHELL: "/bin/bash" # To prevent https://github.com/kubernetes/minikube/issues/6643
-    runs-on: macos-12
+    runs-on: macos-10.15
     steps:
       - name: Install kubectl
         shell: bash
diff --git a/.github/workflows/time-to-k8s-public-chart.yml b/.github/workflows/time-to-k8s-public-chart.yml
index f75c4ebcf..56fbb1d26 100644
--- a/.github/workflows/time-to-k8s-public-chart.yml
+++ b/.github/workflows/time-to-k8s-public-chart.yml
@@ -31,7 +31,7 @@ jobs:
           ./hack/benchmark/time-to-k8s/public-chart/public-chart.sh docker containerd
   time-to-k8s-public-chart-virtualbox:
     if: github.repository == 'kubernetes/minikube'
-    runs-on: macos-12
+    runs-on: macos-10.15
     env:
       AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
       AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
diff --git a/cmd/minikube/cmd/config/config.go b/cmd/minikube/cmd/config/config.go
index 4af7698da..9fd368535 100644
--- a/cmd/minikube/cmd/config/config.go
+++ b/cmd/minikube/cmd/config/config.go
@@ -168,6 +168,10 @@ var settings = []Setting{
 		name: config.Rootless,
 		set:  SetBool,
 	},
+	{
+		name: config.MaxAuditEntries,
+		set:  SetInt,
+	},
 }
 
 // ConfigCmd represents the config command
diff --git a/cmd/minikube/cmd/root.go b/cmd/minikube/cmd/root.go
index dea3f0ee5..e61486672 100644
--- a/cmd/minikube/cmd/root.go
+++ b/cmd/minikube/cmd/root.go
@@ -325,6 +325,7 @@ func setupViper() {
 	viper.SetDefault(config.ReminderWaitPeriodInHours, 24)
 	viper.SetDefault(config.WantNoneDriverWarning, true)
 	viper.SetDefault(config.WantVirtualBoxDriverWarning, true)
+	viper.SetDefault(config.MaxAuditEntries, 1000)
 }
 
 func addToPath(dir string) {
diff --git a/hack/benchmark/time-to-k8s/time-to-k8s-repo b/hack/benchmark/time-to-k8s/time-to-k8s-repo
index a1f382413..6e6133456 160000
--- a/hack/benchmark/time-to-k8s/time-to-k8s-repo
+++ b/hack/benchmark/time-to-k8s/time-to-k8s-repo
@@ -1,1 +1,1 @@
-Subproject commit a1f382413bb7f572f198167f58fbb3abbf51d38b
+Subproject commit 6e6133456e56553c341fd1a8a465fd302d85123d
diff --git a/pkg/minikube/audit/audit.go b/pkg/minikube/audit/audit.go
index 2f945f7ce..8292bb227 100644
--- a/pkg/minikube/audit/audit.go
+++ b/pkg/minikube/audit/audit.go
@@ -98,6 +98,9 @@ func LogCommandEnd(id string) error {
 		return err
 	}
 	var entriesNeedsToUpdate int
+
+	startIndex := getStartIndex(len(rowSlice))
+	rowSlice = rowSlice[startIndex:]
 	for _, v := range rowSlice {
 		if v.id == id {
 			v.endTime = time.Now().Format(constants.TimeFormat)
@@ -118,6 +121,15 @@ func LogCommandEnd(id string) error {
 	return nil
 }
 
+func getStartIndex(entryCount int) int {
+	maxEntries := viper.GetInt(config.MaxAuditEntries)
+	startIndex := entryCount - maxEntries
+	if maxEntries <= 0 || startIndex <= 0 {
+		return 0
+	}
+	return startIndex
+}
+
 // shouldLog returns if the command should be logged.
 func shouldLog() bool {
 	// in rare chance we get here without a command, don't log
diff --git a/pkg/minikube/config/config.go b/pkg/minikube/config/config.go
index d93352604..1f93ce6de 100644
--- a/pkg/minikube/config/config.go
+++ b/pkg/minikube/config/config.go
@@ -54,6 +54,8 @@ const (
 	AddonListFlag = "addons"
 	// EmbedCerts represents the config for embedding certificates in kubeconfig
 	EmbedCerts = "EmbedCerts"
+	// MaxAuditEntries is the maximum number of audit entries to retain
+	MaxAuditEntries = "MaxAuditEntries"
 )
 
 var (


Test patch:
diff --git a/pkg/minikube/audit/audit_test.go b/pkg/minikube/audit/audit_test.go
index 262ceac82..3397850bf 100644
--- a/pkg/minikube/audit/audit_test.go
+++ b/pkg/minikube/audit/audit_test.go
@@ -17,8 +17,11 @@ limitations under the License.
 package audit
 
 import (
+	"io"
 	"os"
+	"os/exec"
 	"os/user"
+	"strings"
 	"testing"
 
 	"github.com/spf13/pflag"
@@ -27,6 +30,33 @@ import (
 )
 
 func TestAudit(t *testing.T) {
+	var auditFilename string
+
+	t.Run("setup", func(t *testing.T) {
+		f, err := os.CreateTemp("", "audit.json")
+		if err != nil {
+			t.Fatalf("failed creating temporary file: %v", err)
+		}
+		auditFilename = f.Name()
+
+		s := `{"data":{"args":"-p mini1","command":"start","endTime":"Wed, 03 Feb 2021 15:33:05 MST","profile":"mini1","startTime":"Wed, 03 Feb 2021 15:30:33 MST","user":"user1"},"datacontenttype":"application/json","id":"9b7593cb-fbec-49e5-a3ce-bdc2d0bfb208","source":"https://minikube.sigs.k8s.io/","specversion":"1.0","type":"io.k8s.si  gs.minikube.audit"}
+{"data":{"args":"-p mini1","command":"start","endTime":"Wed, 03 Feb 2021 15:33:05 MST","profile":"mini1","startTime":"Wed, 03 Feb 2021 15:30:33 MST","user":"user1"},"datacontenttype":"application/json","id":"9b7593cb-fbec-49e5-a3ce-bdc2d0bfb208","source":"https://minikube.sigs.k8s.io/","specversion":"1.0","type":"io.k8s.si  gs.minikube.audit"}
+{"data":{"args":"--user user2","command":"logs","endTime":"Tue, 02 Feb 2021 16:46:20 MST","profile":"minikube","startTime":"Tue, 02 Feb 2021 16:46:00 MST","user":"user2"},"datacontenttype":"application/json","id":"fec03227-2484-48b6-880a-88fd010b5efd","source":"https://minikube.sigs.k8s.io/","specversion":"1.0","type":"io.k8s.sigs.minikube.audit"}
+{"data":{"args":"-p mini1","command":"start","endTime":"Wed, 03 Feb 2021 15:33:05 MST","profile":"mini1","startTime":"Wed, 03 Feb 2021 15:30:33 MST","user":"user1"},"datacontenttype":"application/json","id":"9b7593cb-fbec-49e5-a3ce-bdc2d0bfb208","source":"https://minikube.sigs.k8s.io/","specversion":"1.0","type":"io.k8s.si  gs.minikube.audit"}
+{"data":{"args":"--user user2","command":"logs","endTime":"Tue, 02 Feb 2021 16:46:20 MST","profile":"minikube","startTime":"Tue, 02 Feb 2021 16:46:00 MST","user":"user2"},"datacontenttype":"application/json","id":"fec03227-2484-48b6-880a-88fd010b5efd","source":"https://minikube.sigs.k8s.io/","specversion":"1.0","type":"io.k8s.sigs.minikube.audit"}
+`
+
+		if _, err := f.WriteString(s); err != nil {
+			t.Fatalf("failed writing to file: %v", err)
+		}
+		if _, err := f.Seek(0, io.SeekStart); err != nil {
+			t.Fatalf("failed seeking to start of file: %v", err)
+		}
+
+		currentLogFile = f
+		viper.Set(config.MaxAuditEntries, 3)
+	})
+
 	t.Run("username", func(t *testing.T) {
 		u, err := user.Current()
 		if err != nil {
@@ -168,7 +198,6 @@ func TestAudit(t *testing.T) {
 			mockArgs(t, test.args)
 
 			got := isDeletePurge()
-
 			if got != test.want {
 				t.Errorf("test.args = %q; isDeletePurge() = %t; want %t", test.args, got, test.want)
 			}
@@ -211,11 +240,18 @@ func TestAudit(t *testing.T) {
 		if err != nil {
 			t.Fatal("start failed")
 		}
-		err = LogCommandEnd(auditID)
+		if err := LogCommandEnd(auditID); err != nil {
+			t.Fatal(err)
+		}
 
+		b, err := exec.Command("wc", "-l", auditFilename).Output()
 		if err != nil {
 			t.Fatal(err)
 		}
+		if !strings.Contains(string(b), "3") {
+			t.Errorf("MaxAuditEntries did not work, expected 3 lines in the audit log found %s", string(b))
+		}
+
 	})
 
 	t.Run("LogCommandEndNonExistingID", func(t *testing.T) {