Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reject user texts matching a regex and provide the reason to the client-side #88

Open
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

davidegirardi
Copy link

@davidegirardi davidegirardi commented Jan 30, 2025

Sometimes users send something they really should not in their rageshake descriptions. I propose here an approach to reject rageshakes whose description matches a regex. The rejection reason is reflected client-side so the user's client can show them want went wrong.

The sample config file provides a regex to reject user texts that could contain a recovery key.

TODO if we like this approach:

  • Update docs/blocked_rageshake.md
  • Update main_test.go
  • Update submit_test.go
  • Update changelog

@davidegirardi davidegirardi marked this pull request as ready for review January 30, 2025 09:02
Copy link
Member

@richvdh richvdh left a comment

Choose a reason for hiding this comment

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

looks sensible in principle. A few thoughts.

main.go Outdated Show resolved Hide resolved
main.go Outdated Show resolved Hide resolved
main.go Outdated Show resolved Hide resolved
main.go Outdated
if l == c.Label {
labelMatch = true
break
func (c RejectionCondition) shouldReject(appName, version string, labels []string, userText string) (reject bool, reason string) {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe I've been writing Rust too long, but I don't love the fact that (false, "blah") is a meaningless response.

Could maybe just return *string here, with nil meaning "do not reject" and anything else being the reason to reject.

Copy link
Author

Choose a reason for hiding this comment

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

Fixed in afd59fd.

Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is fixed. shouldReject and matchesRejectionCondition both still return a bool and a *string, meaning that they can return nonsensical things like (false, "blah").

Recommend making them return just *string.

@davidegirardi davidegirardi marked this pull request as draft January 31, 2025 11:52
@davidegirardi
Copy link
Author

I think it's ready for review again. I abused the Data attribute to add an expected rejection reason in the tests. I don't know if that's OK.

@davidegirardi davidegirardi marked this pull request as ready for review January 31, 2025 12:22
@davidegirardi davidegirardi requested a review from richvdh January 31, 2025 12:22
main.go Outdated Show resolved Hide resolved
main.go Outdated Show resolved Hide resolved
main.go Outdated
if l == c.Label {
labelMatch = true
break
func (c RejectionCondition) shouldReject(appName, version string, labels []string, userText string) (reject bool, reason string) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is fixed. shouldReject and matchesRejectionCondition both still return a bool and a *string, meaning that they can return nonsensical things like (false, "blah").

Recommend making them return just *string.

main.go Outdated
if appName != c.App {
return false
// shouldReject returns true if all the App, Version, Label and UserTextMatch attributes of a RejectionCondition match
func (c RejectionCondition) shouldReject(appName, version string, labels []string, userText string) (reject bool, reason *string) {
Copy link
Member

Choose a reason for hiding this comment

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

I think it woldl be cleaner to take a *payload rather than have this ever-growing list of parameters.

Copy link
Author

Choose a reason for hiding this comment

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

Done, I also moved the version extraction logic into shoudReject from matchesRejectionCondition to do it cleanly.

main_test.go Show resolved Hide resolved
main.go Outdated
if appName != c.App {
return false
// shouldReject returns a rejection reason if the payload matches the condition, nil if the server should accept the rageshake
// gocyclo: ignore we need lots of checks because all fields are optional
Copy link
Author

Choose a reason for hiding this comment

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

Gocyclo wants a comment //gocyclo:ignore on a line by itself to ignore a function. Unfortunately go fmt will add a space there // gocyclo:ignore. Can I raise the cyclomatic dependency in the linting script from 12 to 13?

Copy link
Member

@richvdh richvdh Feb 5, 2025

Choose a reason for hiding this comment

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

sorry, forgot to respond to this. (Feel free to "request review", it helps me remember there is something to come back to.)

I'm really not enthusiastic about increasing the cyclomatic complexity limit at all, either locally or globally. Whilst it can feel arbitrary, and to some extent the exact limit is arbitrary, it's there for a reason, and is intended to help remind us when it's time to break down a function into smaller parts rather than waiting for a function to get huge. If we increase the limit every time we hit it, we defeat the purpose.

In this case: sorry, but you've broken the camel's back. It's time to split up shouldReject. How about a set of functions like

func (c RejectionCondition) matchesApp(p *payload) bool {
	// Empty `RejectionCondition.App` is a wildcard which matches anything
	return c.App == "" || c.App == p.AppName
}

func (c RejectionCondition) matchesVersion(p *payload) bool {
	version := ""
	if p.Data != nil {
		version = p.Data["Version"]
	}
	// Empty `RejectionCondition.Version` is a wildcard which matches anything
	return c.Version == "" || c.Version == version
}

... and then put those together in the obvious manner in shouldReject ?

Copy link
Author

Choose a reason for hiding this comment

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

I'll think about it but IMO it will make the code harder, not easier, to follow. Let's see where I land.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants