Skip to content

Commit

Permalink
feat: version 3.24 (#82)
Browse files Browse the repository at this point in the history
* feat: version 3.24

* chore: run updated black over the codebase

* chore: add profiling files

* chore: downgrade message editing failure to debug instead of warning

* chore: bump logoo to 1.4.0 to reduce log upload failures

* chore: move suggestions security violations to a higher handler for more metadata in logs

* chore: bump logoo version

* feat: add german translations

* fix: blocklist remove without args

Closes BT-38

* Update pt_BR.json (#83)

* chore: move stats.py to logoo

* feat: add SECURITY.md

* fix: missing info in ConfiguredChannelNoLongerExists error

Closes BT-42

* chore: remove overkill data

* feat: add the notes command

Also fix a whole bunch of other stuff

* fix: tests

* feat: make thread pings configurable at the user level

BT-41

* feat: finish guild configs and localizing

BT-41

* fix: localization

Closes #73

* chore: remove a test we no longer needed

* add todo

* feat: allow resolving queued suggestions with notes

BT-22

* fix: errors not propagating in some situations

BT-49

* feat: log on missing base translation

* fix: missing base translations

* pt-BR localization updates and fixes for version 3.24 (#87)

* Update pt_BR.json to version 3.24

* Clarify the pt-BR translation

* Update en_GB.json

---------

Co-authored-by: Davi <[email protected]>
  • Loading branch information
Skelmis and Davi-the-Mudkip authored Jun 9, 2024
1 parent 60aa4f0 commit 1f9cbad
Show file tree
Hide file tree
Showing 31 changed files with 1,004 additions and 199 deletions.
18 changes: 18 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
## Summary
<!-- What is this pull request for? -->
<!-- If this is not a version PR, remove the following -->
## Documentation changes

- XXX

## Minor changes

- XXX

## Bug fixes

- XXX

## Technical changes

- XXX

<!-- Delete to here -->

## Checklist

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ examples/dev.py
docs/_build
test/
*.prof
profile.json
profile.html

suggestions/telemetry/error_telemetry_tracebacks
suggestions/telemetry/forbidden_errors
Expand Down
48 changes: 48 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Security Policy

## Supported Versions

The latest master branch is actively maintained and any security patches will be applied to that branch.

Older versions will not have patches back ported.

## Reporting a Vulnerability

### TLDR

We recommend opening a security advisory on GitHub, as per the [documentation](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability).

Alternatively, reach out to the maintainers via discord (`@skelmis`).

---

### Your research

We ask that anyone conducting testing:
- Makes every effort to avoid impacting other users of our systems
- Avoids any activities that disrupt, degrade or interrupt our services or may compromise other user data. This includes things such as spam, brute forcing, DoS, etc
- Keeps vulnerability information private until we have had the ability to roll out fixes


### Our commitment

If you meet the expectations laid out, we commit to:
- Acknowledge any reports and keeping you informed of how we are tracking on fixes
- Acting in good faith when interacting with you
- Recognising your contribution via means such as security advisories on the affected services and/or CVE's


We will aim to fix any issues ASAP, however as we are not a dedicated resource this may not always be possible. As such, we aim for full resolution to all acknowledged issues within a 90-day period. If this is not possible, we will enter discussions with you as to the reason for delays.


### Report details

At a minimum, your report should contain:
- The affected service
- A description of the vulnerability
- Complete reproduction steps

You may include other items to your report as you please. Some examples may be:
- The perceived impact
- The perceived likelihood of exploitation
- A list of users to credit for the disclosure
1 change: 1 addition & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ async def run_bot():
TOKEN = os.environ["PROD_TOKEN"] if bot.is_prod else os.environ["TOKEN"]

log.info("About to start SuggestionsBot | %s", bot.version)
log.info("We are in prod" if bot.is_prod else "We are launching in non-prod")
await bot.start(TOKEN)


Expand Down
96 changes: 33 additions & 63 deletions suggestions/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
MissingQueueLogsChannel,
MissingPermissionsToAccessQueueChannel,
InvalidFileType,
SuggestionSecurityViolation,
)
from suggestions.http_error_parser import try_parse_http_error
from suggestions.interaction_handler import InteractionHandler
Expand All @@ -55,7 +56,7 @@

class SuggestionsBot(commands.AutoShardedInteractionBot, BotBase):
def __init__(self, *args, **kwargs):
self.version: str = "Public Release 3.23"
self.version: str = "Public Release 3.24"
self.main_guild_id: int = 601219766258106399
self.legacy_beta_role_id: int = 995588041991274547
self.automated_beta_role_id: int = 998173237282361425
Expand Down Expand Up @@ -415,6 +416,26 @@ async def on_slash_command_error(
)
)

elif isinstance(exception, SuggestionSecurityViolation):
logger.critical(
"User %s looked up a suggestion from a different guild",
interaction.author.id,
extra_metadata={
"guild_id": interaction.guild_id,
"suggestion_id": exception.suggestion_id,
"author_id": interaction.author.id,
},
)
return await interaction.send(
embed=self.error_embed(
"Command failed",
exception.user_facing_message,
error_code=ErrorCode.SUGGESTION_NOT_FOUND,
error=error,
),
ephemeral=True,
)

elif isinstance(exception, commands.MissingPermissions):
perms = ",".join(i for i in exception.missing_permissions)
return await interaction.send(
Expand Down Expand Up @@ -500,7 +521,8 @@ async def on_slash_command_error(
embed=self.error_embed(
"Configuration Error",
"I cannot find your configured channel for this command.\n"
"Please ask an administrator to reconfigure one.",
"Please ask an administrator to reconfigure one.\n"
"This can be done using: `/config channel`",
error_code=ErrorCode.CONFIGURED_CHANNEL_NO_LONGER_EXISTS,
error=error,
),
Expand Down Expand Up @@ -660,7 +682,6 @@ async def load(self):
await self.stats.load()
await self.update_bot_listings()
await self.push_status()
await self.update_dev_channel()
await self.watch_for_shutdown_request()
await self.load_cogs()
await self.zonis.start()
Expand Down Expand Up @@ -724,65 +745,6 @@ async def process_watch_for_shutdown():
process_watch_for_shutdown.__task = task_1
state.add_background_task(task_1)

async def update_dev_channel(self):
if not self.is_prod:
log.info("Not watching for debug info as not on prod")
return

if not self.is_primary_cluster:
log.info("Not watching for debug info as not primary cluster")
return

state: State = self.state

async def process_watch_for_shutdown():
await self.wait_until_ready()
log.debug("Started tracking bot latency")

while not state.is_closing:
# Update once an hour
await self.sleep_with_condition(
datetime.timedelta(minutes=5).total_seconds(),
lambda: self.state.is_closing,
)

await self.garven.notify_devs(
title=f"WS latency as follows",
description=f"Timestamped for {datetime.datetime.utcnow().isoformat()}",
sender=f"N/A",
)

data = await self.garven.get_bot_ws_latency()
shard_data = data["shards"]
for i in range(0, 75, 5):
description = io.StringIO()
for o in range(0, 6):
shard = str(i + o)
try:
description.write(
f"**Shard {shard}**\nWS latency: `{shard_data[shard]['ws']}`\n"
f"Keep Alive latency: `{shard_data[shard]['keepalive']}`\n\n"
)
except KeyError:
# My lazy way of not doing env checks n math right
continue

if description.getvalue():
await self.garven.notify_devs(
title=f"WS latency",
description=description.getvalue(),
sender=f"Partial response: {data['partial_response']}",
)

await self.sleep_with_condition(
datetime.timedelta(hours=1).total_seconds(),
lambda: self.state.is_closing,
)

task_1 = asyncio.create_task(process_watch_for_shutdown())
process_watch_for_shutdown.__task = task_1
state.add_background_task(task_1)

async def update_bot_listings(self) -> None:
"""Updates the bot lists with current stats."""
if not self.is_prod:
Expand Down Expand Up @@ -869,7 +831,15 @@ def get_locale(self, key: str, locale: Locale) -> str:
return values[str(locale)]
except KeyError:
# Default to known translations if not set
return values.get("en-GB", values["en-US"])
value = values.get("en-GB")
if value is None:
value = values["en-US"]
logger.critical(
"Missing translation in en-GB file",
extra_metadata={"translation_key": key},
)

return value

@staticmethod
def inject_locale_values(
Expand Down
4 changes: 2 additions & 2 deletions suggestions/clunk2/edits.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ async def update_suggestion_message(
# We do this to avoid a race condition where the suggestion may have
# had a value modified between when it was added to the edit queue
# and the time at which it was actually edited
up_to_date_suggestion = await bot.state.suggestions_db.find(suggestion)
up_to_date_suggestion: Suggestion = await bot.state.suggestions_db.find(suggestion)
try:
await MessageEditing(
bot,
channel_id=up_to_date_suggestion.channel_id,
message_id=up_to_date_suggestion.message_id,
).edit(embed=await up_to_date_suggestion.as_embed(bot))
except (disnake.HTTPException, disnake.NotFound) as e:
logger.error(
logger.debug(
"Failed to update suggestion %s",
suggestion.suggestion_id,
extra_metadata={
Expand Down
6 changes: 6 additions & 0 deletions suggestions/cogs/blacklist_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ async def remove(
ephemeral=True,
)

if user_id is None and suggestion_id is None:
return await interaction.send(
"Either a suggestion_id or user_id is required.",
ephemeral=True,
)

if suggestion_id:
suggestion: Suggestion = await Suggestion.from_id(
suggestion_id, interaction.guild_id, self.state
Expand Down
62 changes: 61 additions & 1 deletion suggestions/cogs/guild_config_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ async def get(
"Using channel queue",
"Queue channel",
"Queue rejection channel",
"Ping on suggestion thread creation",
],
default=None,
),
Expand Down Expand Up @@ -244,6 +245,16 @@ async def get(
)
embed.description += log_channel

elif config == "Ping on suggestion thread creation":
locale_string = (
"CONFIG_GET_INNER_USES_THREAD_PINGS_SET"
if guild_config.ping_on_thread_creation
else "CONFIG_GET_INNER_USES_THREAD_PINGS_NOT_SET"
)
text = self.bot.get_localized_string(locale_string, interaction)

embed.description += text

elif config == "Queue channel":
log_channel = (
self.bot.get_locale(
Expand Down Expand Up @@ -536,6 +547,15 @@ async def send_full_config(self, interaction: disnake.GuildCommandInteraction):
"CONFIG_GET_INNER_AUTO_ARCHIVE_THREADS_MESSAGE", interaction.locale
).format(auto_archive_threads_text)

ping_on_thread_creation = (
"CONFIG_GET_INNER_USES_THREAD_PINGS_SET"
if guild_config.ping_on_thread_creation
else "CONFIG_GET_INNER_USES_THREAD_PINGS_NOT_SET"
)
ping_on_thread_creation = self.bot.get_localized_string(
ping_on_thread_creation, interaction
)

locale_string = (
"CONFIG_GET_INNER_SUGGESTIONS_QUEUE_SET"
if guild_config.uses_suggestion_queue
Expand All @@ -560,7 +580,7 @@ async def send_full_config(self, interaction: disnake.GuildCommandInteraction):
f"Suggestion threads: {threads}\nKeep Logs: {keep_logs}\nAnonymous suggestions: {anon}\n"
f"Automatic thread archiving: {auto_archive_threads}\nSuggestions queue: {suggestions_queue}\n"
f"Channel queue: {physical_queue}\nImages in suggestions: {images}\n"
f"Anonymous resolutions: {anonymous_resolutions}\n"
f"Anonymous resolutions: {anonymous_resolutions}\nPings in new suggestion threads: {ping_on_thread_creation}\n"
f"Queue channel: {queue_channel}\nQueue rejection channel: {queue_rejection_channel}",
color=self.bot.colors.embed_color,
timestamp=self.bot.state.now,
Expand Down Expand Up @@ -673,6 +693,46 @@ async def thread_disable(self, interaction: disnake.GuildCommandInteraction):
self.stats.type.GUILD_THREAD_DISABLE,
)

@config.sub_command_group()
async def ping_on_thread_creation(
self, interaction: disnake.GuildCommandInteraction
):
pass

@ping_on_thread_creation.sub_command(name="enable")
async def ping_on_thread_creation_enable(
self, interaction: disnake.GuildCommandInteraction
):
"""Enable pings when a thread is created on a suggestion."""
await self.modify_guild_config(
interaction,
"ping_on_thread_creation",
True,
self.bot.get_locale(
"CONFIG_PING_ON_THREAD_CREATION_ENABLE_INNER_MESSAGE",
interaction.locale,
),
"Enabled pings on new suggestion threads for guild %s",
self.stats.type.GUILD_PING_ON_THREAD_CREATE_ENABLE,
)

@ping_on_thread_creation.sub_command(name="disable")
async def ping_on_thread_creation_disable(
self, interaction: disnake.GuildCommandInteraction
):
"""Disable pings when a thread is created on a suggestion."""
await self.modify_guild_config(
interaction,
"ping_on_thread_creation",
False,
self.bot.get_locale(
"CONFIG_PING_ON_THREAD_CREATION_DISABLE_INNER_MESSAGE",
interaction.locale,
),
"Disabled pings on new suggestion threads for guild %s",
self.stats.type.GUILD_PING_ON_THREAD_CREATE_DISABLE,
)

@config.sub_command_group()
async def keeplogs(self, interaction: disnake.GuildCommandInteraction):
pass
Expand Down
Loading

0 comments on commit 1f9cbad

Please sign in to comment.