add SNS receiver subject validation#2829
Conversation
Signed-off-by: Yijie Qin <qinyijie@amazon.com>
79e2447 to
4fea185
Compare
…sns-subject-validation
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>
|
Note to myself: are we already doing Trimspaces to remove extra spaces before or after the subject? |
|
|
||
| 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) |
There was a problem hiding this comment.
| 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) |
| } | ||
|
|
||
| // 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) |
There was a problem hiding this comment.
| 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) |
There was a problem hiding this comment.
We should maybe not output the full message if its' very long
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| var logger = log.NewNopLogger() |
There was a problem hiding this comment.
can we avoid this as a top level variable?
| 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) |
There was a problem hiding this comment.
| 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) |
| ) | ||
|
|
||
| const ( | ||
| // Message components |
There was a problem hiding this comment.
| // Message components | |
| // Message components. |
| // Message components | ||
| Subject = "Subject" | ||
|
|
||
| // Modified Message attribute value format |
There was a problem hiding this comment.
| // Modified Message attribute value format | |
| // Modified message attribute format. |
| // Modified Message attribute value format | ||
| ComponentAndModifiedReason = "%s: %s" | ||
|
|
||
| // The errors |
There was a problem hiding this comment.
| // The errors | |
| // Errors messages. |
Signed-off-by: Yijie Qin <qinyijie@amazon.com>
Signed-off-by: Yijie Qin <qinyijie@amazon.com>
roidelapluie
left a comment
There was a problem hiding this comment.
cc @gotjosh for a 2nd look
gotjosh
left a comment
There was a problem hiding this comment.
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.
| return nil | ||
| } | ||
|
|
||
| func validateAndTruncateMessage(message string, maxMessageSizeInBytes int) (string, bool, error) { |
There was a problem hiding this comment.
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.
| @@ -43,3 +51,172 @@ func TestValidateAndTruncateMessage(t *testing.T) { | |||
| _, _, err = validateAndTruncateMessage(invalidUtf8String, 100) | |||
There was a problem hiding this comment.
| _, _, err = validateAndTruncateMessage(invalidUtf8String, 100) | |
| const maxMessageSize = 100 | |
| _, _, err = validateAndTruncateMessage(invalidUtf8String, maxMessageSize) |
And move maxMessageSize to the top of the file.
There was a problem hiding this comment.
this is testing variables, add some comments
| "github.com/prometheus/alertmanager/types" | ||
| ) | ||
|
|
||
| const ( |
There was a problem hiding this comment.
nit: Is there any reason why these are public, can we make them private?
| } | ||
|
|
||
| templatedSubject := tmpl(n.conf.Subject) | ||
| if n.conf.Subject != "" || templatedSubject != "" { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
| 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) |
There was a problem hiding this comment.
| 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") |
There was a problem hiding this comment.
No need to show an empty subject.
|
|
||
| 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) |
There was a problem hiding this comment.
| 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) |
| *modifiedReasons = append(*modifiedReasons, fmt.Sprintf(ComponentAndModifiedReason, Subject, fmt.Sprintf(SubjectSizeExceeded, charactersInSubject))) | ||
| return subject[:subjectSizeLimitInCharacters] |
There was a problem hiding this comment.
| *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) |
|
Hello from the Alertmanager bug scrub. This change needs a rebase. |
Add validation for subject