Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 6, 2025

  • Add GuildRoleUpdate event handler to DiscordIntegrator
  • Implement handler to check if modified role is a managed role (all roles in RoleMap)
  • Query Discord audit log to determine who made the modification
  • Filter out bot-initiated changes
  • Send audit message to guild audit channel with modification details
  • Include role type identification in audit messages
  • Address PR review feedback (refactor role type logic, fix duplicate logging)
  • Validate implementation with manual testing (requires live Discord environment)

Implementation Details:

  • Monitors all managed roles: Member, Enforcer, Auditor, ServerHost, Allocator, Suspended, APIAccess, AccountAgeBypass, VPNBypass, AccountLinked (primary focus), and UsernameOnly
  • Includes role type in audit messages for better clarity
  • Provides detailed change information from Discord audit logs
  • Skips bot-initiated changes to prevent duplicate notifications
  • Refactored role type determination into reusable GetRoleType() helper method
Original prompt

This section details on the original issue you should resolve

<issue_title>Emit audit message when a managed role is modified by a non-bot user</issue_title>
<issue_description>When a managed role (e.g. the linked role) within a guild is modified by anyone other than the bot, the system should emit an audit message to the guild's audit channel. This ensures that all changes to managed roles are properly tracked and can be reviewed for security and compliance purposes.

Requirements:

  • Detect modifications to managed roles, specifically the linked role, within each guild.
  • If the modification is performed by a user other than the bot, send an audit message to the designated audit channel for that guild.
  • The audit message should include relevant details such as the user who made the change, timestamp, and details of the modification.
  • Ensure the implementation does not send duplicate messages for bot-initiated changes.

Rationale:

  • Provides a clear audit trail for sensitive role changes.
  • Enhances transparency and accountability within guild administration.
  • Improves detection of unauthorized or unexpected changes to managed roles.

Acceptance Criteria:

  • Audit messages are reliably sent when non-bot users change managed roles.
  • No audit messages are sent for actions performed by the bot itself.
  • Audit messages contain sufficient detail for guild administrators to review.

If available, please reference related code responsible for role management and event handling in your implementation.</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

thesprockee and others added 16 commits October 15, 2025 12:40
- Implement BeforeWriteStorageObjectsHook and BeforeDeleteStorageObjectsHook to enforce StorageObjects intent (or IsGlobalOperator) and block unauthorized write/delete requests by returning nil.
- Clarify AfterReadStorageObjectsHook comment to specify retry when zero objects were returned.
- Small TODO placement fix in BeforeListMatchesHook.
- Comment out registration of the BeforeWriteStorageObjects guard in registerAPIGuards.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Andrew Bates <a@sprock.io>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Andrew Bates <a@sprock.io>
* Initial plan

* Add nakama-debug to .gitignore

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>
Co-authored-by: Andrew Bates <a@sprock.io>
…tion (#124)

* Initial plan

* Extract common storage authorization logic into helper function

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>
Co-authored-by: Andrew Bates <a@sprock.io>
…ing (#127)

* Initial plan

* Add novalidation tag support for game server registration

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

* Add documentation for novalidation tag

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

* Use constant for novalidation tag to avoid magic string

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

* Make audit message sending async and clarify documentation

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>
Co-authored-by: Andrew Bates <a@sprock.io>
…ions (#128)

* Initial plan

* Extract common authorization logic into helper function

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

---------

Signed-off-by: Andrew Bates <a@sprock.io>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>
Co-authored-by: Andrew Bates <a@sprock.io>
…130)

* Initial plan

* Add nakama-debug to .gitignore

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

* Conditionally show moderator Discord ID in suspension embeds

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

* Add tests for conditional enforcer ID display in suspension embeds

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>
Co-authored-by: Andrew Bates <a@sprock.io>
* Initial plan

* Initial analysis - Identify error message improvement needed

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

* Update error messages to include internal IP, external IP, and port

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>
Co-authored-by: Andrew Bates <a@sprock.io>
Use the loop variable (gID) instead of the outer groupID when calling
createSuspensionDetailsEmbedField so each embed field references the
correct guild instead of always using the current group.
* Initial plan

* Initial plan for fixing Past Display Names embed bug

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

* Fix Past Display Names embed bug and add missing ServerEventsPublish method

- Fixed timestamp assignment bug in createPastDisplayNameEmbed where variable 'e' was being assigned instead of 'ts'
- Added comprehensive test coverage for createPastDisplayNameEmbed function
- Fixed Satori build issue by implementing missing ServerEventsPublish method

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>
Co-authored-by: Andrew Bates <a@sprock.io>
Germ-99 and others added 6 commits November 6, 2025 06:35
* Added IGN Override lock toggle and interaction for user metadata

* Update server/evr_discord_appbot_handlers.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Andrew Bates <a@sprock.io>

* Update server/evr_discord_appbot_igp.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Andrew Bates <a@sprock.io>

* Update server/evr_discord_appbot.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Andrew Bates <a@sprock.io>

---------

Signed-off-by: Andrew Bates <a@sprock.io>
Co-authored-by: Andrew Bates <a@sprock.io>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Andrew Bates <a@sprock.io>
Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>
Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>
@thesprockee thesprockee marked this pull request as ready for review November 6, 2025 12:51
Copilot AI review requested due to automatic review settings November 6, 2025 12:51
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds monitoring and audit logging for Discord role modifications. When a managed role in a tracked guild is updated by a non-bot user, the system now sends an audit message to the guild's audit channel with details about who made the change and what was modified.

Key changes:

  • Added a new handleGuildRoleUpdate event handler in the DiscordIntegrator
  • Integrated the handler into the Start() method to listen for GuildRoleUpdate events
  • Created a comprehensive test file documenting expected behavior (all tests currently skipped)

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
server/evr_discord_integrator.go Adds handler registration in Start() method and implements handleGuildRoleUpdate function to audit managed role changes
server/evr_discord_integrator_roleupdate_test.go Adds skipped documentation tests describing the expected behavior of role update handling

Comment on lines 12 to 23
func TestHandleGuildRoleUpdate_NotTrackedGuild(t *testing.T) {
// This test would require mocking the DiscordIntegrator and its dependencies
// Since the codebase doesn't have an established mocking pattern for this component,
// we're documenting the expected behavior:
//
// Given: A GuildRoleUpdate event for a guild that is not in our system
// When: handleGuildRoleUpdate is called
// Then: The function should return nil without sending any audit messages
//
// This is handled by the groupID check on line 910-914 in evr_discord_integrator.go
t.Skip("Test requires extensive mocking infrastructure")
}
Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

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

All test functions in this file are skipped with no actual test implementation. Per the custom guideline 1000000, only EVR unit tests should be included. While documentation tests can be useful, these skipped tests provide no test coverage. Consider either implementing actual unit tests using table-driven test patterns (similar to evr_enforcement_journal_test.go and evr_discord_appbot_test.go), or removing these skipped documentation tests entirely since they don't provide executable coverage.

Copilot generated this review using guidance from repository custom instructions.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed in b9de6f8. The skipped documentation tests have been deleted since they provide no executable coverage. Actual unit tests for this feature would require extensive mocking infrastructure that doesn't currently exist in the codebase.

Comment on lines 929 to 953
roleType := "unknown"
switch e.Role.ID {
case guildGroup.RoleMap.AccountLinked:
roleType = "linked"
case guildGroup.RoleMap.Member:
roleType = "member"
case guildGroup.RoleMap.Enforcer:
roleType = "enforcer"
case guildGroup.RoleMap.Auditor:
roleType = "auditor"
case guildGroup.RoleMap.ServerHost:
roleType = "server_host"
case guildGroup.RoleMap.Allocator:
roleType = "allocator"
case guildGroup.RoleMap.Suspended:
roleType = "suspended"
case guildGroup.RoleMap.APIAccess:
roleType = "api_access"
case guildGroup.RoleMap.AccountAgeBypass:
roleType = "account_age_bypass"
case guildGroup.RoleMap.VPNBypass:
roleType = "vpn_bypass"
case guildGroup.RoleMap.UsernameOnly:
roleType = "username_only"
}
Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

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

[nitpick] This large switch statement to determine roleType could be refactored into a helper method on GuildGroupRoles (similar to AsSlice() and AsSet()). This would improve maintainability and keep role-related logic centralized in the GuildGroupRoles type. Consider adding a method like GetRoleType(roleID string) string to the GuildGroupRoles struct.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactored in b9de6f8. Added GetRoleType() helper method to GuildGroupRoles, centralizing role-related logic as suggested.

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>
Copilot AI requested a review from thesprockee November 6, 2025 13:13
…ion-again

Signed-off-by: Andrew Bates <a@sprock.io>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Andrew Bates <a@sprock.io>
@thesprockee
Copy link
Member

@copilot

try again.

…e logging

- Extract roleType determination into GetRoleType helper method on GuildGroupRoles
- Remove duplicate error logging (let caller handle it)
- Remove skipped documentation tests that provide no executable coverage

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 20, 2025

@copilot

try again.

Could you clarify what you'd like me to try again? The PR currently implements:

  • GuildRoleUpdate event handler with audit logging
  • GetRoleType() helper method on GuildGroupRoles
  • Fixed duplicate error logging
  • Removed skipped test file

What specific aspect would you like me to revisit or change?

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.

Emit audit message when a managed role is modified by a non-bot user

3 participants