Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions internal/adc/translator/apisixconsumer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package translator
import (
"fmt"
"strconv"
"strings"

"github.com/pkg/errors"
k8stypes "k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -307,15 +308,25 @@ func (t *Translator) translateConsumerHMACAuthPlugin(tctx *provider.TranslateCon
}

clockSkewRaw := sec.Data["clock_skew"]
clockSkew, _ := strconv.ParseInt(string(clockSkewRaw), 10, 64)
var clockSkew int64
if len(clockSkewRaw) > 0 {
var err error
clockSkew, err = strconv.ParseInt(string(clockSkewRaw), 10, 64)
if err != nil {
return nil, fmt.Errorf("hmac-auth: invalid clock_skew %q in secret: %w", string(clockSkewRaw), err)
}
}
if clockSkew < 0 {
clockSkew = _hmacAuthClockSkewDefaultValue
}

// comma-separated header names, not raw bytes
signedHeadersRaw := sec.Data["signed_headers"]
signedHeaders := make([]string, 0, len(signedHeadersRaw))
for _, b := range signedHeadersRaw {
signedHeaders = append(signedHeaders, string(b))
var signedHeaders []string
for _, h := range strings.Split(string(signedHeadersRaw), ",") {
if h = strings.TrimSpace(h); h != "" {
signedHeaders = append(signedHeaders, h)
}
}

var keepHeader bool
Expand Down Expand Up @@ -355,7 +366,14 @@ func (t *Translator) translateConsumerHMACAuthPlugin(tctx *provider.TranslateCon
}

maxReqBodyRaw := sec.Data["max_req_body"]
maxReqBody, _ := strconv.ParseInt(string(maxReqBodyRaw), 10, 64)
var maxReqBody int64
if len(maxReqBodyRaw) > 0 {
var err error
maxReqBody, err = strconv.ParseInt(string(maxReqBodyRaw), 10, 64)
if err != nil {
return nil, fmt.Errorf("hmac-auth: invalid max_req_body %q in secret: %w", string(maxReqBodyRaw), err)
}
}
if maxReqBody < 0 {
maxReqBody = _hmacAuthMaxReqBodyDefaultValue
}
Expand Down
51 changes: 51 additions & 0 deletions internal/adc/translator/apisixconsumer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,64 @@ import (

"github.com/go-logr/logr"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8stypes "k8s.io/apimachinery/pkg/types"

adctypes "github.com/apache/apisix-ingress-controller/api/adc"
apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
"github.com/apache/apisix-ingress-controller/internal/controller/label"
"github.com/apache/apisix-ingress-controller/internal/provider"
)

func hmacConsumerWithSecret(name string) *apiv2.ApisixConsumer {
return &apiv2.ApisixConsumer{
ObjectMeta: metav1.ObjectMeta{Name: "demo", Namespace: "default"},
Spec: apiv2.ApisixConsumerSpec{
AuthParameter: &apiv2.ApisixConsumerAuthParameter{
HMACAuth: &apiv2.ApisixConsumerHMACAuth{
SecretRef: &corev1.LocalObjectReference{Name: name},
},
},
},
}
}

func TestTranslateApisixConsumer_HMACAuthSignedHeadersFromSecret(t *testing.T) {
translator := NewTranslator(logr.Discard())
tctx := provider.NewDefaultTranslateContext(context.Background())
tctx.Secrets[k8stypes.NamespacedName{Namespace: "default", Name: "hmac"}] = &corev1.Secret{
Data: map[string][]byte{
"key_id": []byte("my-key"),
"secret_key": []byte("my-secret"),
"signed_headers": []byte("X-Date, Host"),
},
}

result, err := translator.TranslateApisixConsumer(tctx, hmacConsumerWithSecret("hmac"))
require.NoError(t, err)
require.Len(t, result.Consumers, 1)

cfg := result.Consumers[0].Plugins["hmac-auth"].(*adctypes.HMACAuthConsumerConfig)
require.Equal(t, []string{"X-Date", "Host"}, cfg.SignedHeaders)
}

func TestTranslateApisixConsumer_HMACAuthRejectsInvalidClockSkew(t *testing.T) {
translator := NewTranslator(logr.Discard())
tctx := provider.NewDefaultTranslateContext(context.Background())
tctx.Secrets[k8stypes.NamespacedName{Namespace: "default", Name: "hmac"}] = &corev1.Secret{
Data: map[string][]byte{
"key_id": []byte("my-key"),
"secret_key": []byte("my-secret"),
"clock_skew": []byte("3O0"), // typo: letter O
},
}

_, err := translator.TranslateApisixConsumer(tctx, hmacConsumerWithSecret("hmac"))
require.Error(t, err)
require.Contains(t, err.Error(), "clock_skew")
}
Comment on lines +68 to +82

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Cover the remaining changed parsing paths.

Add cases for invalid max_req_body and empty signed_headers entries; the current inputs do not verify either new behavior.

Proposed test adjustments
-			"signed_headers": []byte("X-Date, Host"),
+			"signed_headers": []byte(" X-Date, , Host, "),
+func TestTranslateApisixConsumer_HMACAuthRejectsInvalidMaxReqBody(t *testing.T) {
+	translator := NewTranslator(logr.Discard())
+	tctx := provider.NewDefaultTranslateContext(context.Background())
+	tctx.Secrets[k8stypes.NamespacedName{Namespace: "default", Name: "hmac"}] = &corev1.Secret{
+		Data: map[string][]byte{
+			"key_id":       []byte("my-key"),
+			"secret_key":   []byte("my-secret"),
+			"max_req_body": []byte("invalid"),
+		},
+	}
+
+	_, err := translator.TranslateApisixConsumer(tctx, hmacConsumerWithSecret("hmac"))
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "max_req_body")
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/adc/translator/apisixconsumer_test.go` around lines 68 - 82, Extend
TestTranslateApisixConsumer_HMACAuthRejectsInvalidClockSkew with cases covering
an invalid max_req_body value and an empty entry in signed_headers. For each
case, configure the corresponding secret data, call TranslateApisixConsumer, and
assert an error mentioning the affected field, while preserving the existing
clock_skew coverage.


func TestTranslateApisixConsumer_UsesMetadataLabelsWithoutOverwritingControllerLabels(t *testing.T) {
translator := NewTranslator(logr.Discard())
tctx := provider.NewDefaultTranslateContext(context.Background())
Expand Down
Loading