diff --git a/cmd/automod/helpers.go b/cmd/automod/helpers.go new file mode 100644 index 0000000..b1a5ed9 --- /dev/null +++ b/cmd/automod/helpers.go @@ -0,0 +1,85 @@ +package main + +import ( + comatproto "github.com/bluesky-social/indigo/api/atproto" + toolsozone "github.com/bluesky-social/indigo/api/ozone" + "github.com/bluesky-social/indigo/atproto/syntax" + "github.com/bluesky-social/indigo/automod" +) + +func addAccountLabel(c *automod.RecordContext, did syntax.DID, label string) error { + am := c.GetAccountMeta(did) + eng := c.InternalEngine() + if eng.OzoneClient == nil { + c.Logger.Warn("skipping label addition", "did", did, "label", label) + return nil + } + + // check if label is already applied + for _, l := range am.AccountLabels { + if l == label { + return nil + } + } + + // send label via engine + c.Logger.Warn("adding label", "did", did, "label", label) + comment := "auto-adding label" + _, err := toolsozone.ModerationEmitEvent(c.Ctx, eng.OzoneClient, &toolsozone.ModerationEmitEvent_Input{ + CreatedBy: eng.OzoneClient.Auth.Did, + Event: &toolsozone.ModerationEmitEvent_Input_Event{ + ModerationDefs_ModEventLabel: &toolsozone.ModerationDefs_ModEventLabel{ + CreateLabelVals: []string{label}, + NegateLabelVals: []string{}, + Comment: &comment, + }, + }, + Subject: &toolsozone.ModerationEmitEvent_Input_Subject{ + AdminDefs_RepoRef: &comatproto.AdminDefs_RepoRef{ + Did: did.String(), + }, + }, + }) + return err +} + +func removeAccountLabel(c *automod.RecordContext, did syntax.DID, label string) error { + am := c.GetAccountMeta(did) + eng := c.InternalEngine() + if eng.OzoneClient == nil { + c.Logger.Warn("skipping label removal", "did", did, "label", label) + return nil + } + + // check if label is already applied + exists := false + for _, l := range am.AccountLabels { + if l == label { + exists = true + break + } + } + if !exists { + return nil + } + + // send label via engine + c.Logger.Warn("removing label", "did", did, "label", label) + comment := "auto-removing label" + _, err := toolsozone.ModerationEmitEvent(c.Ctx, eng.OzoneClient, &toolsozone.ModerationEmitEvent_Input{ + CreatedBy: eng.OzoneClient.Auth.Did, + Event: &toolsozone.ModerationEmitEvent_Input_Event{ + ModerationDefs_ModEventLabel: &toolsozone.ModerationDefs_ModEventLabel{ + CreateLabelVals: []string{}, + NegateLabelVals: []string{label}, + Comment: &comment, + }, + }, + Subject: &toolsozone.ModerationEmitEvent_Input_Subject{ + AdminDefs_RepoRef: &comatproto.AdminDefs_RepoRef{ + Did: did.String(), + }, + }, + }) + return err +} diff --git a/cmd/automod/main.go b/cmd/automod/main.go index e6d604c..933307a 100644 --- a/cmd/automod/main.go +++ b/cmd/automod/main.go @@ -93,7 +93,7 @@ func run(args []string) error { &cli.IntFlag{ Name: "firehose-parallelism", Usage: "force a fixed number of parallel firehose workers. default (or 0) for auto-scaling; 200 works for a large instance", - Value: 200, + Value: 200, EnvVars: []string{"AUTOMOD_FIREHOSE_PARALLELISM"}, }, } diff --git a/cmd/automod/rules.go b/cmd/automod/rules.go index 034ffd7..6878e77 100644 --- a/cmd/automod/rules.go +++ b/cmd/automod/rules.go @@ -22,12 +22,12 @@ func GoodbotBadbotRule(c *automod.RecordContext, post *appbsky.FeedPost) error { return nil } - authorDid := c.Account.Identity.DID.String() + authorDID := c.Account.Identity.DID if post.Reply == nil || IsSelfThread(c, post) { mentionedDids := mentionedDids(post) - for _, botDid := range mentionedDids { - handleBotSignal(c, botDid, authorDid, botType) + for _, botDID := range mentionedDids { + handleBotSignal(c, botDID, authorDID, botType) } return nil } @@ -36,25 +36,32 @@ func GoodbotBadbotRule(c *automod.RecordContext, post *appbsky.FeedPost) error { return nil } - botDid := parentURI.Authority().String() - handleBotSignal(c, botDid, authorDid, botType) - + botDID, err := parentURI.Authority().AsDID() + if err != nil { + return err + } + handleBotSignal(c, botDID, authorDID, botType) return nil } -func handleBotSignal(c *automod.RecordContext, botDid string, authorDid string, botType int) { +func handleBotSignal(c *automod.RecordContext, botDID string, authorDID string, botType int) { if botType == 1 { - c.IncrementDistinct("goodbot", botDid, authorDid) - c.IncrementDistinct("bladerunner", authorDid, botDid) + c.IncrementDistinct("goodbot", botDID, authorDID) + c.IncrementDistinct("bladerunner", authorDID, botDID) c.Logger.Error("good bot reply") - if c.GetCountDistinct("goodbot", botDid, countstore.PeriodTotal) > GOOD_BOT_REPLY_THRESHOLD-1 { + // XXX: bypass counts for early testing + if err = addAccountLabel(c, botDID, "good-bot"); err != nil { + return err + } + + if c.GetCountDistinct("goodbot", botDID, countstore.PeriodTotal) > GOOD_BOT_REPLY_THRESHOLD-1 { c.Logger.Error("good bot") // c.AddAccountLabel("good-bot") // c.Notify("slack") } - if c.GetCountDistinct("bladerunner", authorDid, countstore.PeriodTotal) > BLADERUNNER_THRESHOLD-1 { + if c.GetCountDistinct("bladerunner", authorDID, countstore.PeriodTotal) > BLADERUNNER_THRESHOLD-1 { c.Logger.Error("bladerunner") // c.AddAccountLabel("bladerunner") // c.Notify("slack") @@ -63,18 +70,18 @@ func handleBotSignal(c *automod.RecordContext, botDid string, authorDid string, return } - c.IncrementDistinct("badbot", botDid, authorDid) - c.IncrementDistinct("jabroni", authorDid, botDid) + c.IncrementDistinct("badbot", botDID, authorDID) + c.IncrementDistinct("jabroni", authorDID, botDID) c.Logger.Error("bad bot reply") - if c.GetCountDistinct("badbot", botDid, countstore.PeriodTotal) > BAD_BOT_REPLY_THRESHOLD-1 { + if c.GetCountDistinct("badbot", botDID, countstore.PeriodTotal) > BAD_BOT_REPLY_THRESHOLD-1 { // @TODO: this would add label to the reply author's account not the parent/bot's account // c.AddAccountLabel("bad-bot") c.Logger.Error("bad bot") // c.Notify("slack") } - if c.GetCountDistinct("jabroni", authorDid, countstore.PeriodTotal) > JABRONI_THRESHOLD-1 { + if c.GetCountDistinct("jabroni", authorDID, countstore.PeriodTotal) > JABRONI_THRESHOLD-1 { // c.AddAccountLabel("jabroni") c.Logger.Error("jabroni") // c.Notify("slack") diff --git a/go.mod b/go.mod index 0525171..aad540d 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,12 @@ module github.com/bluesky-social/bladerunner-club go 1.22.2 require ( - github.com/bluesky-social/indigo v0.0.0-20241022184456-f49cfdb05a3b + github.com/bluesky-social/indigo v0.0.0-20241022192011-1b2d84c83f3b github.com/carlmjohnson/versioninfo v0.22.5 github.com/joho/godotenv v1.5.1 github.com/prometheus/client_golang v1.17.0 github.com/redis/go-redis/v9 v9.3.0 + github.com/stretchr/testify v1.9.0 github.com/urfave/cli/v2 v2.25.7 golang.org/x/time v0.3.0 ) @@ -82,7 +83,6 @@ require ( github.com/puzpuzpuz/xsync/v3 v3.0.2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/stretchr/testify v1.9.0 // indirect github.com/vmihailenco/go-tinylfu v0.2.2 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index ed9e1c0..b06d175 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,8 @@ github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bluesky-social/indigo v0.0.0-20241022184456-f49cfdb05a3b h1:vPd4Ydvqh/K8xbDeRmBFEoEr1iNtgUj0/1cMlvGD8Z4= -github.com/bluesky-social/indigo v0.0.0-20241022184456-f49cfdb05a3b/go.mod h1:Zx9nSWgd/FxMenkJW07VKnzspxpHBdPrPmS+Fspl2I0= +github.com/bluesky-social/indigo v0.0.0-20241022192011-1b2d84c83f3b h1:Qu4WUVEPJ9K11Q/TlzKsgzlDjai6nUNswwEAuCe8tMw= +github.com/bluesky-social/indigo v0.0.0-20241022192011-1b2d84c83f3b/go.mod h1:Zx9nSWgd/FxMenkJW07VKnzspxpHBdPrPmS+Fspl2I0= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=