From c9fb423f8dda8956fd0b10582c354e9366b6469c Mon Sep 17 00:00:00 2001 From: faizanahmad055 Date: Mon, 12 Jan 2026 19:33:26 +0100 Subject: [PATCH 1/2] Use SHA512 instead of SHA1 Signed-off-by: faizanahmad055 --- docs/How-it-works.md | 4 ++-- docs/Reloader-vs-ConfigmapController.md | 14 +++++++------- docs/Reloader-vs-k8s-trigger-controller.md | 2 +- internal/pkg/crypto/sha.go | 16 ++++------------ internal/pkg/crypto/sha_test.go | 6 +++--- internal/pkg/handler/upgrade_test.go | 12 ++++++------ 6 files changed, 23 insertions(+), 31 deletions(-) diff --git a/docs/How-it-works.md b/docs/How-it-works.md index c0ae964ff..1f4b7e1e7 100644 --- a/docs/How-it-works.md +++ b/docs/How-it-works.md @@ -76,7 +76,7 @@ Note: Rolling upgrade also works in the same way for secrets. ### Hash Value Computation -Reloader uses SHA1 to compute hash value. SHA1 is used because it is efficient and less prone to collision. +Reloader uses SHA512 to compute hash value. SHA512 is used because it is efficient and less prone to collision. ## Monitor All Namespaces @@ -90,4 +90,4 @@ The output file can then be used to deploy Reloader in specific namespace. ## Compatibility With Helm Install and Upgrade -Reloader has no impact on helm deployment cycle. Reloader only injects an environment variable in `deployment`, `daemonset` or `statefulset`. The environment variable contains the SHA1 value of `ConfigMaps` or `Secrets` data. So if a deployment is created using Helm and Reloader updates the deployment, then next time you upgrade the helm release, Reloader will do nothing except changing that environment variable value in `deployment` , `daemonset` or `statefulset`. +Reloader has no impact on helm deployment cycle. Reloader only injects an environment variable in `deployment`, `daemonset` or `statefulset`. The environment variable contains the SHA512 value of `ConfigMaps` or `Secrets` data. So if a deployment is created using Helm and Reloader updates the deployment, then next time you upgrade the helm release, Reloader will do nothing except changing that environment variable value in `deployment` , `daemonset` or `statefulset`. diff --git a/docs/Reloader-vs-ConfigmapController.md b/docs/Reloader-vs-ConfigmapController.md index 1433daa52..3ddab0827 100644 --- a/docs/Reloader-vs-ConfigmapController.md +++ b/docs/Reloader-vs-ConfigmapController.md @@ -2,10 +2,10 @@ Reloader is inspired from [`configmapcontroller`](https://github.com/fabric8io/configmapcontroller) but there are many ways in which it differs from `configmapcontroller`. Below is the small comparison between these two controllers. -| Reloader | ConfigMap | -|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Reloader can watch both `Secrets` and `ConfigMaps`. | `configmapcontroller` can only watch changes in `ConfigMaps`. It cannot detect changes in other resources like `Secrets`. | -| Reloader can perform rolling upgrades on `deployments` as well as on `statefulsets` and `daemonsets` | `configmapcontroller` can only perform rolling upgrades on `deployments`. It currently does not support rolling upgrades on `statefulsets` and `daemonsets` | -| Reloader provides both unit test cases and end to end integration test cases for future updates. So one can make sure that new changes do not break any old functionality. | Currently there are not any unit test cases or end to end integration test cases in `configmap-controller`. It adds difficulties for any additional updates in `configmap-controller` and one can not know for sure whether new changes breaks any old functionality or not. | -| Reloader uses SHA1 to encode the change in `ConfigMap` or `Secret`. It then saves the SHA1 value in `STAKATER_FOO_CONFIGMAP` or `STAKATER_FOO_SECRET` environment variable depending upon where the change has happened. The use of SHA1 provides a concise 40 characters encoded value that is very less prone to collision. | `configmap-controller` uses `FABRICB_FOO_REVISION` environment variable to store any change in `ConfigMap` controller. It does not encode it or convert it in suitable hash value to avoid data pollution in deployment. | -| Reloader allows you to customize your own annotation (for both `Secrets` and `ConfigMaps`) using command line flags | `configmap-controller` restricts you to only their provided annotation | +| Reloader | ConfigMap | +|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Reloader can watch both `Secrets` and `ConfigMaps`. | `configmapcontroller` can only watch changes in `ConfigMaps`. It cannot detect changes in other resources like `Secrets`. | +| Reloader can perform rolling upgrades on `deployments` as well as on `statefulsets` and `daemonsets` | `configmapcontroller` can only perform rolling upgrades on `deployments`. It currently does not support rolling upgrades on `statefulsets` and `daemonsets` | +| Reloader provides both unit test cases and end to end integration test cases for future updates. So one can make sure that new changes do not break any old functionality. | Currently there are not any unit test cases or end to end integration test cases in `configmap-controller`. It adds difficulties for any additional updates in `configmap-controller` and one can not know for sure whether new changes breaks any old functionality or not. | +| Reloader uses SHA512 to encode the change in `ConfigMap` or `Secret`. It then saves the SHA1 value in `STAKATER_FOO_CONFIGMAP` or `STAKATER_FOO_SECRET` environment variable depending upon where the change has happened. The use of SHA1 provides a concise 40 characters encoded value that is very less prone to collision. | `configmap-controller` uses `FABRICB_FOO_REVISION` environment variable to store any change in `ConfigMap` controller. It does not encode it or convert it in suitable hash value to avoid data pollution in deployment. | +| Reloader allows you to customize your own annotation (for both `Secrets` and `ConfigMaps`) using command line flags | `configmap-controller` restricts you to only their provided annotation | diff --git a/docs/Reloader-vs-k8s-trigger-controller.md b/docs/Reloader-vs-k8s-trigger-controller.md index 561dca505..fe0f6d979 100644 --- a/docs/Reloader-vs-k8s-trigger-controller.md +++ b/docs/Reloader-vs-k8s-trigger-controller.md @@ -6,7 +6,7 @@ Reloader and k8s-trigger-controller are both built for same purpose. So there ar - Both controllers support change detection in `ConfigMaps` and `Secrets` - Both controllers support deployment `rollout` -- Reloader controller use SHA1 for hashing +- Reloader controller use SHA512 for hashing - Both controllers have end to end as well as unit test cases. ## Differences diff --git a/internal/pkg/crypto/sha.go b/internal/pkg/crypto/sha.go index 043fc2273..af38c1f9d 100644 --- a/internal/pkg/crypto/sha.go +++ b/internal/pkg/crypto/sha.go @@ -1,20 +1,12 @@ package crypto import ( - "crypto/sha1" - "fmt" - "io" - - "github.com/sirupsen/logrus" + "crypto/sha512" + "encoding/hex" ) // GenerateSHA generates SHA from string func GenerateSHA(data string) string { - hasher := sha1.New() - _, err := io.WriteString(hasher, data) - if err != nil { - logrus.Errorf("Unable to write data in hash writer %v", err) - } - sha := hasher.Sum(nil) - return fmt.Sprintf("%x", sha) + hash := sha512.Sum512_256([]byte(data)) + return hex.EncodeToString(hash[:]) } diff --git a/internal/pkg/crypto/sha_test.go b/internal/pkg/crypto/sha_test.go index 5cb0afc69..6ee7c2b8b 100644 --- a/internal/pkg/crypto/sha_test.go +++ b/internal/pkg/crypto/sha_test.go @@ -7,7 +7,7 @@ import ( // TestGenerateSHA generates the sha from given data and verifies whether it is correct or not func TestGenerateSHA(t *testing.T) { data := "www.stakater.com" - sha := "abd4ed82fb04548388a6cf3c339fd9dc84d275df" + sha := "2e9aa975331b22861b4f62b7fcc69b63e001f938361fee3b4ed888adf26a10e3" result := GenerateSHA(data) if result != sha { t.Errorf("Failed to generate SHA") @@ -18,11 +18,11 @@ func TestGenerateSHA(t *testing.T) { // This ensures consistent behavior and avoids issues with string matching operations func TestGenerateSHAEmptyString(t *testing.T) { result := GenerateSHA("") - expected := "da39a3ee5e6b4b0d3255bfef95601890afd80709" + expected := "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a" if result != expected { t.Errorf("Failed to generate SHA for empty string. Expected: %s, Got: %s", expected, result) } - if len(result) != 40 { + if len(result) != 64 { t.Errorf("SHA hash should be 40 characters long, got %d", len(result)) } } diff --git a/internal/pkg/handler/upgrade_test.go b/internal/pkg/handler/upgrade_test.go index 68ba94dec..e905ee03a 100644 --- a/internal/pkg/handler/upgrade_test.go +++ b/internal/pkg/handler/upgrade_test.go @@ -1981,7 +1981,7 @@ func TestRollingUpgradeForDeploymentWithPatchAndRetryUsingArs(t *testing.T) { assert.Equal(t, patchtypes.StrategicMergePatchType, patchType) assert.NotEmpty(t, bytes) assert.Contains(t, string(bytes), `{"spec":{"template":{"metadata":{"annotations":{"reloader.stakater.com/last-reloaded-from":`) - assert.Contains(t, string(bytes), `\"hash\":\"3c9a892aeaedc759abc3df9884a37b8be5680382\"`) + assert.Contains(t, string(bytes), `\"hash\":\"fd9e71a362056bfa864d9859e12978f893d330ce8cbf09218b25d015770ad91f\"`) return nil } @@ -2964,7 +2964,7 @@ func TestRollingUpgradeForDaemonSetWithPatchAndRetryUsingArs(t *testing.T) { assert.Equal(t, patchtypes.StrategicMergePatchType, patchType) assert.NotEmpty(t, bytes) assert.Contains(t, string(bytes), `{"spec":{"template":{"metadata":{"annotations":{"reloader.stakater.com/last-reloaded-from":`) - assert.Contains(t, string(bytes), `\"hash\":\"314a2269170750a974d79f02b5b9ee517de7f280\"`) + assert.Contains(t, string(bytes), `\"hash\":\"43bf9e30e7c4e32a8f8673c462b86d0b1ac626cf498afdc0d0108e79ebe7ee0c\"`) return nil } @@ -3227,7 +3227,7 @@ func TestRollingUpgradeForStatefulSetWithPatchAndRetryUsingArs(t *testing.T) { assert.Equal(t, patchtypes.StrategicMergePatchType, patchType) assert.NotEmpty(t, bytes) assert.Contains(t, string(bytes), `{"spec":{"template":{"metadata":{"annotations":{"reloader.stakater.com/last-reloaded-from":`) - assert.Contains(t, string(bytes), `\"hash\":\"f821414d40d8815fb330763f74a4ff7ab651d4fa\"`) + assert.Contains(t, string(bytes), `\"hash\":\"6aa837180bdf6a93306c71a0cf62b4a45c2d5b021578247b3b64d5baea2b84d9\"`) return nil } @@ -3607,7 +3607,7 @@ func TestRollingUpgradeForDeploymentWithPatchAndRetryUsingErs(t *testing.T) { assert.Equal(t, patchtypes.StrategicMergePatchType, patchType) assert.NotEmpty(t, bytes) assert.Contains(t, string(bytes), `{"spec":{"template":{"spec":{"containers":[{"name":`) - assert.Contains(t, string(bytes), `"value":"3c9a892aeaedc759abc3df9884a37b8be5680382"`) + assert.Contains(t, string(bytes), `"value":"fd9e71a362056bfa864d9859e12978f893d330ce8cbf09218b25d015770ad91f"`) return nil } @@ -4502,7 +4502,7 @@ func TestRollingUpgradeForDaemonSetWithPatchAndRetryUsingErs(t *testing.T) { assert.Equal(t, patchtypes.StrategicMergePatchType, patchType) assert.NotEmpty(t, bytes) assert.Contains(t, string(bytes), `{"spec":{"template":{"spec":{"containers":[{"name":`) - assert.Contains(t, string(bytes), `"value":"314a2269170750a974d79f02b5b9ee517de7f280"`) + assert.Contains(t, string(bytes), `"value":"43bf9e30e7c4e32a8f8673c462b86d0b1ac626cf498afdc0d0108e79ebe7ee0c"`) return nil } @@ -4737,7 +4737,7 @@ func TestRollingUpgradeForStatefulSetWithPatchAndRetryUsingErs(t *testing.T) { assert.Equal(t, patchtypes.StrategicMergePatchType, patchType) assert.NotEmpty(t, bytes) assert.Contains(t, string(bytes), `{"spec":{"template":{"spec":{"containers":[{"name":`) - assert.Contains(t, string(bytes), `"value":"f821414d40d8815fb330763f74a4ff7ab651d4fa"`) + assert.Contains(t, string(bytes), `"value":"6aa837180bdf6a93306c71a0cf62b4a45c2d5b021578247b3b64d5baea2b84d9"`) return nil } From 64251979c3a2dc4ef15493614042c0f4d3dd76c1 Mon Sep 17 00:00:00 2001 From: faizanahmad055 Date: Sun, 5 Apr 2026 22:54:37 +0200 Subject: [PATCH 2/2] Update dependencies Signed-off-by: faizanahmad055 --- .github/workflows/push-helm-chart.yaml | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/push-helm-chart.yaml b/.github/workflows/push-helm-chart.yaml index fc80c05ee..84860ba93 100644 --- a/.github/workflows/push-helm-chart.yaml +++ b/.github/workflows/push-helm-chart.yaml @@ -73,7 +73,7 @@ jobs: exit 1 - name: Install Cosign - uses: sigstore/cosign-installer@v4.0.0 + uses: sigstore/cosign-installer@v4.1.1 - name: Login to GHCR Registry uses: docker/login-action@v3 diff --git a/go.mod b/go.mod index 081b17b02..f31c5976e 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( k8s.io/apimachinery v0.35.3 k8s.io/client-go v0.35.3 k8s.io/kubectl v0.35.3 - sigs.k8s.io/secrets-store-csi-driver v1.5.5 + sigs.k8s.io/secrets-store-csi-driver v1.5.6 ) require ( diff --git a/go.sum b/go.sum index 70a4505f6..0d9307efd 100644 --- a/go.sum +++ b/go.sum @@ -205,8 +205,8 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/secrets-store-csi-driver v1.5.5 h1:LJDpDL5TILhlP68nGvtGSlJFxSDgAD2m148NT0Ts7os= -sigs.k8s.io/secrets-store-csi-driver v1.5.5/go.mod h1:i2WqLicYH00hrTG3JAzICPMF4HL4KMEORlDt9UQoZLk= +sigs.k8s.io/secrets-store-csi-driver v1.5.6 h1:vVghX13yY7AmPEtxTEdMrZzj0uDzAu1kq9EY6mDOfXM= +sigs.k8s.io/secrets-store-csi-driver v1.5.6/go.mod h1:668UPSzWZsWpR6VOcqfx24tcw8sh0RI9LmWOMjHjETc= sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=