Skip to content

add SNS receiver subject validation#2829

Open
qinxx108 wants to merge 8 commits intoprometheus:mainfrom
qinxx108:sns-subject-validation
Open

add SNS receiver subject validation#2829
qinxx108 wants to merge 8 commits intoprometheus:mainfrom
qinxx108:sns-subject-validation

Conversation

@qinxx108
Copy link
Copy Markdown
Contributor

@qinxx108 qinxx108 commented Feb 8, 2022

Add validation for subject

  1. if not ASCII, we will replace it with error message
  2. if longer than 100 characters, we will truncate the subject

Signed-off-by: Yijie Qin <qinyijie@amazon.com>
@qinxx108 qinxx108 force-pushed the sns-subject-validation branch from 79e2447 to 4fea185 Compare February 8, 2022 19:21
qinxx108 and others added 4 commits February 8, 2022 11:27
Signed-off-by: Yijie Qin <qinyijie@amazon.com>
…empty subject

Signed-off-by: Soon-Ping Phang <soonping@amazon.com>
Signed-off-by: Soon-Ping Phang <soonping@amazon.com>
@roidelapluie
Copy link
Copy Markdown
Member

Note to myself: are we already doing Trimspaces to remove extra spaces before or after the subject?

Comment thread notify/sns/sns.go Outdated

if !isASCIINonControl(subject) {
*modifiedReasons = append(*modifiedReasons, fmt.Sprintf(ComponentAndModifiedReason, Subject, SubjectContainsIllegalChars))
level.Info(logger).Log("msg", "subject has been modified because it contains control- or non-ASCII characters", "originalSubject", subject)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
level.Info(logger).Log("msg", "subject has been modified because it contains control- or non-ASCII characters", "originalSubject", subject)
level.Warn(logger).Log("msg", "Subject has been modified because it contains control- or non-ASCII characters.", "originalSubject", subject)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread notify/sns/sns.go Outdated
}

// If the message is larger than our specified size we have to truncate.
level.Info(logger).Log("msg", "subject has been truncated because of size limit exceeded", "originalSubject", subject)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
level.Info(logger).Log("msg", "subject has been truncated because of size limit exceeded", "originalSubject", subject)
level.Warn(logger).Log("msg", "Subject has been truncated because of size limit exceeded.", "originalSubject", subject)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should maybe not output the full message if its' very long

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

removed

Comment thread notify/sns/sns_test.go Outdated
"github.com/stretchr/testify/require"
)

var logger = log.NewNopLogger()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can we avoid this as a top level variable?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Comment thread notify/sns/sns.go Outdated
func validateAndTruncateSubject(logger log.Logger, subject string, modifiedReasons *[]string) string {
if subject == "" {
*modifiedReasons = append(*modifiedReasons, fmt.Sprintf(ComponentAndModifiedReason, Subject, SubjectEmpty))
level.Info(logger).Log("msg", "subject has been modified because it is empty", "originalSubject", subject)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
level.Info(logger).Log("msg", "subject has been modified because it is empty", "originalSubject", subject)
level.Warn(logger).Log("msg", "Subject has been modified because it is empty.", "originalSubject", subject)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Comment thread notify/sns/sns.go Outdated
)

const (
// Message components
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
// Message components
// Message components.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Comment thread notify/sns/sns.go Outdated
// Message components
Subject = "Subject"

// Modified Message attribute value format
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
// Modified Message attribute value format
// Modified message attribute format.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Comment thread notify/sns/sns.go Outdated
// Modified Message attribute value format
ComponentAndModifiedReason = "%s: %s"

// The errors
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
// The errors
// Errors messages.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

qinxx108 added 3 commits May 9, 2022 12:09
Signed-off-by: Yijie Qin <qinyijie@amazon.com>
Signed-off-by: Yijie Qin <qinyijie@amazon.com>
Copy link
Copy Markdown
Member

@roidelapluie roidelapluie left a comment

Choose a reason for hiding this comment

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

cc @gotjosh for a 2nd look

Copy link
Copy Markdown
Member

@gotjosh gotjosh left a comment

Choose a reason for hiding this comment

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

I've dropped a couple of very correctable fixes on the code, but...

My biggest worry is about direction - what we're doing is communicating errors via SNS as opposed to failing to deliver the notification. This seems to go against the approach taken in other receivers where we prefer to fail the notification as opposed to delivering incorrect ones. (I don't have the context, but I presume it might be due to increased costs for incorrect alerts)

Correct me if I'm wrong, but the problem you're trying to solve here is probably the biggest pain point I've seen from Alertmanager: notification failures are hard to communicate back to the user.

If it is, then I'd rather us focus on a more permanent solution that applies to all receivers and not just SNS.

That being said, I just want to hear from @roidelapluie given he already gave a 👍 to this approach. If he thinks we should proceed, I won't block this change and would only expect my changes to be addressed.

Comment thread notify/sns/sns.go
return nil
}

func validateAndTruncateMessage(message string, maxMessageSizeInBytes int) (string, bool, error) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In the error message below we have spelt utf8 as the spelling of UTF-8, can quickly correct that? (I can't comment on that line because it wasn't modified here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Comment thread notify/sns/sns_test.go
@@ -43,3 +51,172 @@ func TestValidateAndTruncateMessage(t *testing.T) {
_, _, err = validateAndTruncateMessage(invalidUtf8String, 100)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
_, _, err = validateAndTruncateMessage(invalidUtf8String, 100)
const maxMessageSize = 100
_, _, err = validateAndTruncateMessage(invalidUtf8String, maxMessageSize)

And move maxMessageSize to the top of the file.

Copy link
Copy Markdown
Contributor Author

@qinxx108 qinxx108 Dec 14, 2022

Choose a reason for hiding this comment

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

this is testing variables, add some comments

Comment thread notify/sns/sns.go
"github.com/prometheus/alertmanager/types"
)

const (
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: Is there any reason why these are public, can we make them private?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Comment thread notify/sns/sns.go
}

templatedSubject := tmpl(n.conf.Subject)
if n.conf.Subject != "" || templatedSubject != "" {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm a bit confused by this validation - you're only using templatedSubject, but your conditional says that if either of - why do we care about n.conf.Subject?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm thinking that it might be because tmpl(n.conf.Subject) can fail but in that case templatedSubject should be n.config.Subject as opposed to "" as it would be here.

You want to inspect err here to know whether it succeeded or not, but you can't because you haven't passed it over to createPublishInput - so I think we're gonna have to re-think the approach.

Comment thread notify/sns/sns.go
func validateAndTruncateSubject(logger log.Logger, subject string, modifiedReasons *[]string) string {
if subject == "" {
*modifiedReasons = append(*modifiedReasons, fmt.Sprintf(ComponentAndModifiedReason, Subject, SubjectEmpty))
level.Warn(logger).Log("msg", "Subject has been modified because it is empty.", "originalSubject", subject)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
level.Warn(logger).Log("msg", "Subject has been modified because it is empty.", "originalSubject", subject)
level.Warn(logger).Log("msg", "subject has been modified because it is empty")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No need to show an empty subject.

Comment thread notify/sns/sns.go

if !isASCIINonControl(subject) {
*modifiedReasons = append(*modifiedReasons, fmt.Sprintf(ComponentAndModifiedReason, Subject, SubjectContainsIllegalChars))
level.Warn(logger).Log("msg", "Subject has been modified because it contains control- or non-ASCII characters.", "originalSubject", subject)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
level.Warn(logger).Log("msg", "Subject has been modified because it contains control- or non-ASCII characters.", "originalSubject", subject)
level.Warn(logger).Log("msg", "subject has been modified because it contains control- or non-ASCII characters", "subject", subject)

Comment thread notify/sns/sns.go
Comment on lines +263 to +264
*modifiedReasons = append(*modifiedReasons, fmt.Sprintf(ComponentAndModifiedReason, Subject, fmt.Sprintf(SubjectSizeExceeded, charactersInSubject)))
return subject[:subjectSizeLimitInCharacters]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
*modifiedReasons = append(*modifiedReasons, fmt.Sprintf(ComponentAndModifiedReason, Subject, fmt.Sprintf(SubjectSizeExceeded, charactersInSubject)))
return subject[:subjectSizeLimitInCharacters]
*modifiedReasons = append(*modifiedReasons, fmt.Sprintf(ComponentAndModifiedReason, Subject, fmt.Sprintf(SubjectSizeExceeded, charactersInSubject)))
truncated := subject[:subjectSizeLimitInCharacters]
level.Warn(logger).Log("msg", "subject has been modified because it exceeds the number of characters allowed", "subject", subject, "truncated", truncated)

@SuperQ
Copy link
Copy Markdown
Member

SuperQ commented Oct 31, 2025

Hello from the Alertmanager bug scrub. This change needs a rebase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants