Skip to content

Conversation

@manas-metron
Copy link

@manas-metron manas-metron commented Jul 17, 2025

Summary by CodeRabbit

  • New Features

    • Added commands for listing Intune devices and compliance, registry-based security analysis, and session security analysis with export and filtering.
    • Introduced Intune registry/script execution and direct sign-in-log collection to enrich device and session telemetry.
    • Added BloodHound-compatible export and richer security analysis (findings, risk scoring, recommendations).
  • Bug Fixes

    • Fixed inconsistent identifier field naming (Id → ID) across multiple list commands.
  • Documentation

    • Added extensive Intune and session data models and enums to support new features.
  • Chores

    • Removed auto-generated mock implementations.
    • Updated .gitignore to exclude workflows and PowerShell scripts.

…etron-azurehound-enhancement-metronlabs

Files are causing a conflict because newly created files were added but the deleted files were not removed.
# Test the current implementation

Build the app using:

go build -ldflags="-s -w -X github.com/bloodhoundad/azurehound/v2/constants.Version=dev-intune"

Then test using added JWT token after these commands:

./azurehound list intune-devices --jwt JWT_TOKEN
./azurehound list intune-data --jwt JWT_TOKEN
./azurehound list intune-compliance --jwt JWT_TOKEN
Add
1. client id
2. client secret &
3. tenant id
for the script to work.
This reverts commit fd673c1.
This reverts commit 160a712.
Removed Unused Methods. Commented Code
@coderabbitai
Copy link

coderabbitai bot commented Jul 17, 2025

Walkthrough

Adds broad Intune and sign-in log support: new Intune models/enums, client methods for device, script, compliance and session collection, CLI commands for Intune device/compliance/registry/session analysis, fixes field-casing, removes an obsolete mock and a directory object model, and updates .gitignore.

Changes

Cohort / File(s) Change Summary
Repository metadata
.gitignore
Added ignore rules for .github workflows and get_token.ps1.
Client interfaces & core
client/client.go
Expanded AzureGraphClient/AzureClient interfaces and added SignInEvent type.
Intune device API implementations
client/intune_devices.go, client/intune_registry.go, client/intune_sessions_direct.go, client/user_roles.go
Implemented Intune device listing, compliance/config queries, script deployment/execution/results retrieval and polling, direct sign-in log collection and session data processing, and enhanced user role/service-account detection.
Mocks removed
client/mocks/client.go
Removed autogenerated GoMock MockAzureClient implementation.
Models — Azure / Intune / Sessions / Security
models/azure/intune.go, models/azure/intune_security.go, models/azure/intune_sessions.go, models/intune/models.go
Added comprehensive Intune, registry, script execution, session, security analysis, and BloodHound-compatible data models.
Models removed / adjusted
models/azure/directory_object.go, models/azure/organization.go
Deleted legacy DirectoryObject; updated Organization.ToTenant() to use ID field.
Enums
enums/intune.go
Added Intune-specific enum types and constants (compliance, enrollment, agent, OS, kinds).
CLI: new Intune commands
cmd/list-intune-devices.go, cmd/list-intune-compliance.go, cmd/list-intune-registry-analysis.go, cmd/list-intune-session-analysis.go
Added commands to list Intune devices, compliance, perform registry-based security analysis, and session security analysis with export/format options.
CLI: field-casing fixes
cmd/list-app-owners.go, cmd/list-app-role-assignments.go, cmd/list-device-owners.go, cmd/list-group-members.go, cmd/list-group-owners.go, cmd/list-role-assignments.go, cmd/list-service-principal-owners.go
Fixed struct field access from Id to ID to match model definitions.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI
    participant AzureClient
    participant MSGraph

    User->>CLI: run "intune-registry-analysis" / "intune-session-analysis"
    CLI->>AzureClient: request devices / sign-in logs / script operations
    AzureClient->>MSGraph: List devices / Get script / Trigger execution / List signInLogs
    MSGraph-->>AzureClient: paginated results / execution status / logs
    AzureClient-->>CLI: stream device/session results (channels)
    CLI->>CLI: analyze results (registry parsing, risk scoring)
    CLI-->>User: display summary, per-device findings, optional export
Loading
sequenceDiagram
    participant AzureClient
    participant MSGraph
    rect rgba(200,230,255,0.6)
        AzureClient->>MSGraph: GetDeployedScriptID(scriptName)
        MSGraph-->>AzureClient: script metadata (ID)
        AzureClient->>MSGraph: TriggerScriptExecution(scriptID, deviceID)
        MSGraph-->>AzureClient: execution acknowledged
        AzureClient->>MSGraph: GetScriptExecutionResults(scriptID) (polling)
        MSGraph-->>AzureClient: execution output / status
    end
    AzureClient->>AzureClient: parse JSON output -> RegistryData
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🐇
I hopped through code, sniffed each log and groove,
Scripts wake, devices chatter, sessions move.
Models sprout like carrots, enums bright and true,
Field names fixed clean — I thumped to say “w00!”
Security bunnies hopping, analysis anew.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "Azurehound enhancement - Active Sessions" is a concise, single-sentence summary that directly relates to the primary changes in the changeset (sign-in/active session collection, session analysis, and related Intune session models/commands); while the word "enhancement" is generic, the phrase "Active Sessions" communicates the main feature added.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d84286a and fda5092.

📒 Files selected for processing (2)
  • client/intune_sessions_direct.go (1 hunks)
  • client/user_roles.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • client/user_roles.go
  • client/intune_sessions_direct.go

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

CLA Assistant Lite bot:
Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 16

🧹 Nitpick comments (13)
client/intune_devices.go (1)

26-26: Consider using a buffered channel for better performance

Using an unbuffered channel may cause the producer goroutine to block frequently. Consider adding a small buffer to improve throughput.

-out  = make(chan AzureResult[intune.ManagedDevice])
+out  = make(chan AzureResult[intune.ManagedDevice], 10)
models/azure/intune.go (3)

33-33: Consider consistent casing for WiFi in JSON tag

The JSON tag "wiFiMacAddress" uses unusual mixed casing. Consider using "wifiMacAddress" for consistency with common naming conventions.

-	WiFiMacAddress                          string        `json:"wiFiMacAddress"`
+	WiFiMacAddress                          string        `json:"wifiMacAddress"`

104-104: Consider documenting expected Settings structure

The Settings field uses map[string]interface{} which is acceptable for variable configuration data. However, consider adding documentation about expected key-value pairs or common settings for better maintainability.

 	LastModifiedDateTime time.Time              `json:"lastModifiedDateTime"`
+	// Settings contains device-specific configuration values.
+	// Common keys include: [list common keys here]
 	Settings             map[string]interface{} `json:"settings"`

140-140: *Consider using string instead of string for Error field

Using *string for the Error field is unusual. Consider using a regular string with an empty string representing no error, or define a custom error type.

 	Values     map[string]interface{} `json:"values"`
 	Accessible bool                   `json:"accessible"`
-	Error      *string                `json:"error"`
+	Error      string                 `json:"error,omitempty"`
models/azure/intune_sessions.go (2)

67-67: Consider using constants or enums for TokenPrivileges

The TokenPrivileges field uses []string which could lead to typos or inconsistent privilege names. Consider defining constants or an enum type for common Windows privileges.

// Example privilege constants
const (
    PrivilegeSeDebug = "SeDebugPrivilege"
    PrivilegeSeBackup = "SeBackupPrivilege"
    PrivilegeSeRestore = "SeRestorePrivilege"
    // ... more privileges
)

285-285: Consider structured format for TechnicalDetails

The TechnicalDetails field is a simple string which might be limiting for complex technical information. Consider using a structured format or allowing markdown/JSON content.

 	EstimatedEffort  string   `json:"estimatedEffort"`
 	MITREMitigations []string `json:"mitreMitigations"`
-	TechnicalDetails string   `json:"technicalDetails"`
+	// TechnicalDetails supports markdown or JSON formatted content
+	TechnicalDetails string   `json:"technicalDetails"`
cmd/list-intune-session-analysis.go (1)

1-1: Add unit tests for the command

The comment indicates this is "without test command". Production code should include comprehensive test coverage.

Would you like me to help create unit tests for this command implementation?

client/intune_registry.go (2)

148-158: Log the primary method failure before fallback

When the assignment method fails, the error is silently swallowed and fallback is attempted. Consider logging the primary failure for debugging purposes.

 _, err := s.msgraph.Post(ctx, path, body, query.GraphParams{}, map[string]string{
     "Content-Type": "application/json",
 })
 if err != nil {
+    // Log the assignment error for debugging
+    // log.Printf("Assignment method failed: %v, trying device action method", err)
     // If assignment method fails, try direct device action
     return s.triggerScriptViaDeviceAction(ctx, scriptID, deviceID)
 }

225-225: Make polling interval configurable

The hard-coded 30-second polling interval might be too long for interactive use or too frequent for long-running scripts. Consider making it configurable.

-ticker := time.NewTicker(30 * time.Second)
+// Allow configurable polling interval with sensible default
+pollInterval := 30 * time.Second
+if customInterval := os.Getenv("INTUNE_POLL_INTERVAL"); customInterval != "" {
+    if duration, err := time.ParseDuration(customInterval); err == nil && duration >= 5*time.Second {
+        pollInterval = duration
+    }
+}
+ticker := time.NewTicker(pollInterval)
cmd/list-intune-registry-analysis.go (2)

33-34: Address the TODO: Script validation is being skipped

The comment indicates that script validation is being skipped temporarily. This should be implemented or properly documented if intentionally omitted.

Would you like me to implement the script validation logic or create an issue to track this TODO?


362-362: Add newlines to Printf statements for proper output formatting

The Printf statements are missing newline characters which could cause output to run together.

Apply this diff to fix the formatting:

-	fmt.Printf("Starting device analysis without script execution...")
+	fmt.Printf("Starting device analysis without script execution...\n")
-	fmt.Printf("Analyzed %d devices based on compliance data", len(results))
+	fmt.Printf("Analyzed %d devices based on compliance data\n", len(results))

Also applies to: 386-386

client/intune_sessions_direct.go (2)

321-366: Consider enhancing role detection heuristics

The current pattern-based detection is a reasonable fallback approach. However, consider these improvements:

  • Document that these are heuristic methods and may have false positives
  • Consider adding configurable pattern lists
  • Log when falling back to heuristic detection

Add documentation to clarify the heuristic nature:

-// Helper functions for role detection
+// Helper functions for role detection using heuristic pattern matching
+// Note: These are fallback methods when API-based detection is unavailable
+// and may produce false positives
 func isAdminUserHeuristic(upn string) bool {

418-422: Optimize regex compilation for GUID detection

The regex pattern is compiled on every function call, which is inefficient. Also, the error from MatchString is ignored.

Move the regex compilation to a package-level variable:

+var guidRegex = regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`)
+
 // Helper function for GUID detection
 func isGUIDLike(s string) bool {
-	guidPattern := `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`
-	matched, _ := regexp.MatchString(guidPattern, s)
-	return matched
+	return guidRegex.MatchString(s)
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fc3ed0f and ff456f4.

📒 Files selected for processing (25)
  • .gitignore (1 hunks)
  • client/client.go (3 hunks)
  • client/intune_devices.go (1 hunks)
  • client/intune_registry.go (1 hunks)
  • client/intune_sessions_direct.go (1 hunks)
  • client/mocks/client.go (0 hunks)
  • client/user_roles.go (1 hunks)
  • cmd/list-app-owners.go (1 hunks)
  • cmd/list-app-role-assignments.go (2 hunks)
  • cmd/list-device-owners.go (1 hunks)
  • cmd/list-group-members.go (1 hunks)
  • cmd/list-group-owners.go (1 hunks)
  • cmd/list-intune-compliance.go (1 hunks)
  • cmd/list-intune-devices.go (1 hunks)
  • cmd/list-intune-registry-analysis.go (1 hunks)
  • cmd/list-intune-session-analysis.go (1 hunks)
  • cmd/list-role-assignments.go (1 hunks)
  • cmd/list-service-principal-owners.go (1 hunks)
  • enums/intune.go (1 hunks)
  • models/azure/directory_object.go (0 hunks)
  • models/azure/intune.go (1 hunks)
  • models/azure/intune_security.go (1 hunks)
  • models/azure/intune_sessions.go (1 hunks)
  • models/azure/organization.go (1 hunks)
  • models/intune/models.go (1 hunks)
💤 Files with no reviewable changes (2)
  • models/azure/directory_object.go
  • client/mocks/client.go
🧰 Additional context used
🧬 Code Graph Analysis (13)
cmd/list-group-members.go (1)
pipeline/pipeline.go (1)
  • Send (35-42)
cmd/list-role-assignments.go (1)
pipeline/pipeline.go (1)
  • Send (35-42)
cmd/list-group-owners.go (1)
pipeline/pipeline.go (1)
  • Send (35-42)
cmd/list-device-owners.go (1)
pipeline/pipeline.go (1)
  • Send (35-42)
cmd/list-app-owners.go (1)
models/app-owner.go (1)
  • AppOwner (24-27)
cmd/list-service-principal-owners.go (1)
pipeline/pipeline.go (1)
  • Send (35-42)
cmd/list-app-role-assignments.go (1)
client/query/params.go (1)
  • GraphParams (109-120)
client/intune_devices.go (4)
client/query/params.go (2)
  • GraphParams (109-120)
  • Top (42-42)
client/client.go (1)
  • AzureResult (120-123)
models/intune/models.go (3)
  • ManagedDevice (12-25)
  • ComplianceState (28-36)
  • ConfigurationState (46-54)
constants/misc.go (1)
  • GraphApiVersion (43-43)
cmd/list-intune-compliance.go (7)
models/intune/models.go (1)
  • ManagedDevice (12-25)
panicrecovery/panic_recovery.go (2)
  • HandleBubbledPanic (14-26)
  • PanicRecovery (29-33)
client/client.go (1)
  • AzureClient (253-273)
pipeline/pipeline.go (1)
  • Demux (109-141)
config/config.go (1)
  • ColStreamCount (308-317)
cmd/utils.go (1)
  • NewAzureWrapper (437-442)
enums/intune.go (1)
  • KindAZIntuneCompliance (8-8)
models/azure/intune.go (4)
enums/intune.go (3)
  • OperatingSystem (45-45)
  • EnrollmentType (24-24)
  • ManagementAgent (35-35)
constants/misc.go (3)
  • DisplayName (29-29)
  • Description (30-30)
  • Name (28-28)
models/azure/device.go (1)
  • Device (28-131)
models/azure/user.go (1)
  • User (25-467)
models/azure/intune_security.go (7)
models/azure/device.go (1)
  • Device (28-131)
models/azure/intune.go (7)
  • IntuneDevice (9-59)
  • SecurityFinding (203-212)
  • EscalationVector (215-225)
  • BloodHoundDeviceData (166-176)
  • DeviceCompliancePolicy (87-94)
  • DeviceConfiguration (97-105)
  • RegistryFinding (189-200)
constants/misc.go (4)
  • DisplayName (29-29)
  • Description (30-30)
  • Version (25-25)
  • Name (28-28)
enums/generic_enabled_disabled.go (1)
  • Enabled (23-23)
models/ingest-request.go (1)
  • Meta (25-29)
enums/intune.go (1)
  • OperatingSystem (45-45)
enums/parameter_type.go (1)
  • ObjectType (28-28)
models/azure/intune_sessions.go (2)
models/azure/device.go (1)
  • Device (28-131)
models/azure/intune.go (3)
  • IntuneDevice (9-59)
  • DeviceInfo (126-132)
  • SecurityIndicators (144-149)
enums/intune.go (2)
enums/kind.go (1)
  • Kind (20-20)
models/intune/models.go (1)
  • ComplianceState (28-36)
🔇 Additional comments (25)
.gitignore (1)

235-238: LGTM - Appropriate ignore rules for CI/CD and sensitive files.

These ignore rules properly exclude GitHub workflow files and the PowerShell token script from version control, which is correct for maintaining security and avoiding unnecessary clutter in the repository.

enums/intune.go (5)

4-9: LGTM - Well-structured Intune Kind constants.

The Kind constants follow the established pattern and use descriptive names that clearly indicate their purpose in the Intune domain.


11-21: LGTM - Comprehensive compliance state enumeration.

The ComplianceState enum covers all standard Microsoft Intune compliance states, including the grace period state which is important for compliance workflows.


23-32: LGTM - Complete enrollment type coverage.

The EnrollmentType enum includes all major Windows enrollment scenarios including Azure AD join, auto-enrollment, and co-management, which provides comprehensive coverage for device enrollment methods.


34-42: LGTM - Appropriate management agent types.

The ManagementAgent enum covers the key management agents used in Microsoft device management, including the fallback "unknown" value for handling unexpected cases.


44-52: LGTM - Standard operating system enumeration.

The OperatingSystem enum includes the major platforms supported by Microsoft Intune with correct casing conventions (iOS, macOS).

cmd/list-group-members.go (1)

91-91: LGTM - Correct field name fix.

The change from group.Id to group.ID properly aligns with Go naming conventions for acronyms and ensures the correct field is accessed from the models.Group struct.

cmd/list-group-owners.go (1)

81-81: LGTM - Consistent field name correction.

The change from group.Id to group.ID maintains consistency with Go naming conventions and ensures proper field access from the models.Group struct.

cmd/list-device-owners.go (1)

80-80: LGTM - Proper field name correction.

The change from device.Id to device.ID correctly follows Go naming conventions for acronyms and ensures the proper field is accessed from the models.Device struct.

cmd/list-role-assignments.go (1)

82-82: Field name correction aligns with Go naming conventions.

The change from role.Id to role.ID properly follows Go naming conventions where acronyms should be capitalized (ID, not Id).

cmd/list-app-owners.go (2)

84-84: Correct field name usage in client method call.

The change from app.Data.Id to app.Data.ID ensures proper access to the application identifier field following Go naming conventions.


90-90: Consistent field name usage in struct assignment.

The change from app.Data.Id to app.Data.ID maintains consistency with the corrected field naming convention in the AppOwner struct assignment.

cmd/list-service-principal-owners.go (1)

81-81: Field name correction follows Go naming conventions.

The change from servicePrincipal.Id to servicePrincipal.ID properly follows Go naming conventions where acronyms should be capitalized.

models/azure/organization.go (2)

130-130: Correct field name usage in tenant ID formatting.

The change from s.Id to s.ID ensures proper access to the organization identifier field following Go naming conventions in the tenant ID formatting.


132-132: Consistent field name usage in TenantId assignment.

The change from s.Id to s.ID maintains consistency with the corrected field naming convention in the TenantId field assignment.

cmd/list-app-role-assignments.go (2)

101-101: Correct field name usage in client method call.

The change from servicePrincipal.Id to servicePrincipal.ID ensures proper access to the service principal identifier field following Go naming conventions.


119-119: Consistent field name usage in logging statement.

The change from servicePrincipal.Id to servicePrincipal.ID maintains consistency with the corrected field naming convention in the logging statement.

models/intune/models.go (1)

1-61: Well-structured data models

The Intune data models are properly defined with appropriate JSON tags and field types that align with Microsoft Graph API responses.

client/client.go (1)

34-34: Import path validated: intune package exists with required types

The import "github.com/bloodhoundad/azurehound/v2/models/intune" is correct. The models/intune/models.go file defines the ManagedDevice, ComplianceState, and ConfigurationState structs as expected. No further action required.

models/azure/intune_sessions.go (1)

8-20: No duplicate DirectoryRole or DirectoryObject definitions found

I searched the entire codebase and confirmed these types only exist in models/azure/intune_sessions.go. There are no conflicting definitions elsewhere, so it’s safe to add them here.

cmd/list-intune-registry-analysis.go (3)

45-68: LGTM!

The function is well-structured with proper error handling for empty results and clear display flow.


290-358: LGTM!

The summary statistics calculation is comprehensive and well-organized. The function properly handles empty results and aggregates data effectively.


480-596: Excellent security analysis implementation!

The function comprehensively checks for various security issues with proper MITRE ATT&CK mapping and detailed escalation vectors. The risk scoring logic is well-balanced.

models/azure/intune_security.go (1)

1-407: Well-structured security data models!

The file provides comprehensive data structures for Intune security analysis and BloodHound integration. Good practices observed:

  • Proper use of JSON tags for serialization
  • Clear naming conventions
  • Appropriate use of time.Time for timestamps
  • Smart naming to avoid conflicts (BloodHoundUser, BloodHoundGroup)
  • Comprehensive security modeling with MITRE ATT&CK integration
client/intune_sessions_direct.go (1)

23-90: Excellent session data collection implementation!

The function handles errors gracefully, provides helpful diagnostic messages when no sign-in logs are found, and follows proper Go patterns with channels and goroutines.

ctx, stop := context.WithCancel(cmd.Context())
defer stop()

azClient := connectAndCreateClient()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for client creation

The connectAndCreateClient() function likely returns an error as a second value. Add proper error handling to ensure graceful failure if the client cannot be created.

-azClient := connectAndCreateClient()
+azClient, err := connectAndCreateClient()
+if err != nil {
+    exit(fmt.Errorf("failed to create Azure client: %w", err))
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
azClient := connectAndCreateClient()
azClient, err := connectAndCreateClient()
if err != nil {
exit(fmt.Errorf("failed to create Azure client: %w", err))
}
🤖 Prompt for AI Agents
In cmd/list-intune-devices.go at line 32, the call to connectAndCreateClient()
is missing error handling. Update the code to capture both the client and error
returned by connectAndCreateClient(), then check if the error is non-nil. If
there is an error, handle it appropriately by logging the error and exiting or
returning early to prevent further execution with an invalid client.

Comment on lines +129 to +152
riskScore := 0
if adminSessions > 0 {
riskScore += adminSessions * 20
}
if totalSessions > 5 {
riskScore += 10
}
if len(deviceData.SessionData.SecurityIndicators.SuspiciousActivities) > 0 {
riskScore += 30
}

analysis.RiskScore = riskScore

// Set security posture
switch {
case riskScore >= 60:
analysis.SecurityPosture = "High_Risk"
case riskScore >= 30:
analysis.SecurityPosture = "Moderate"
case riskScore >= 10:
analysis.SecurityPosture = "Low_Risk"
default:
analysis.SecurityPosture = "Secure"
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use constants for risk scoring thresholds

The risk scoring logic uses magic numbers that make the code difficult to maintain and understand. Define constants for better clarity and maintainability.

+const (
+    // Risk score components
+    RiskScorePerAdminSession = 20
+    RiskScoreHighSessionCount = 10
+    RiskScoreSuspiciousActivity = 30
+    
+    // Risk thresholds
+    RiskThresholdHigh = 60
+    RiskThresholdModerate = 30
+    RiskThresholdLow = 10
+    
+    // Session count threshold
+    SessionCountThresholdHigh = 5
+)

 // Calculate risk score
 riskScore := 0
 if adminSessions > 0 {
-    riskScore += adminSessions * 20
+    riskScore += adminSessions * RiskScorePerAdminSession
 }
-if totalSessions > 5 {
-    riskScore += 10
+if totalSessions > SessionCountThresholdHigh {
+    riskScore += RiskScoreHighSessionCount
 }
 if len(deviceData.SessionData.SecurityIndicators.SuspiciousActivities) > 0 {
-    riskScore += 30
+    riskScore += RiskScoreSuspiciousActivity
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In cmd/list-intune-session-analysis.go around lines 129 to 152, the risk scoring
logic uses hardcoded numeric values (magic numbers) for thresholds and score
increments. Define descriptive constants for these values at the top of the file
or in a dedicated constants section, then replace all occurrences of these magic
numbers with the corresponding constants to improve code clarity and
maintainability.

Comment on lines +436 to +478
// performRealRegistrySecurityAnalysis performs actual registry data collection and analysis
func performRealRegistrySecurityAnalysis(ctx context.Context, azClient client.AzureClient) ([]azure.DeviceSecurityAnalysis, error) {
var (
out = make([]azure.DeviceSecurityAnalysis, 0)
successCount = 0
errorCount = 0
)

fmt.Printf("Starting real registry security analysis...")

// Use the real registry collection function from your client
deviceRegistryData := azClient.CollectRegistryDataFromAllDevices(ctx)

for registryResult := range deviceRegistryData {
if registryResult.Error != nil {
fmt.Printf("Error collecting registry data: %v", registryResult.Error)
errorCount++
continue
}

// Perform real security analysis on the collected registry data
analysis := performBasicDeviceSecurityAnalysis(registryResult.Ok)

// Enhance the analysis with additional checks
enhanceSecurityAnalysis(&analysis, registryResult.Ok)

out = append(out, analysis)
successCount++

fmt.Printf("Analyzed device %s: %d findings, risk score %d",
analysis.Device.DeviceName,
len(analysis.SecurityFindings),
analysis.RiskScore)
}

fmt.Printf("Registry analysis completed: %d successful, %d errors", successCount, errorCount)

if successCount == 0 && errorCount > 0 {
return nil, fmt.Errorf("failed to analyze any devices successfully (%d errors)", errorCount)
}

return out, nil
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Unused function: performRealRegistrySecurityAnalysis

This function appears to be the actual registry security analysis implementation but is never called. The main command only uses performDeviceAnalysisWithoutScripts. This should either be integrated into the command flow or removed if not needed.

Consider either:

  1. Updating the main command to use this function when scripts are available
  2. Removing this dead code if it's no longer needed
  3. Adding a command flag to toggle between simplified and real analysis modes
🤖 Prompt for AI Agents
In cmd/list-intune-registry-analysis.go around lines 436 to 478, the function
performRealRegistrySecurityAnalysis is defined but never called, making it dead
code. To fix this, either integrate this function into the main command flow by
replacing or conditionally calling it instead of
performDeviceAnalysisWithoutScripts, or add a command-line flag to toggle
between the simplified and real analysis modes and call this function
accordingly. If the function is no longer needed, remove it to clean up the
codebase.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (3)
client/user_roles.go (2)

41-70: URL encoding properly implemented

Good implementation addressing the previous review feedback - the userPrincipalName is now properly URL encoded using url.QueryEscape, and the stable v1.0 endpoint is used.


138-161: Correct OData filter syntax implemented

The Filter field now correctly contains only the filter expression without the "$filter=" prefix, addressing the previous review feedback.

client/intune_sessions_direct.go (1)

221-222: Propagate the parent context for role detection

The enhanced role detection functions should use the parent function's context instead of context.Background() to preserve cancellation and deadlines.

-isAdmin := s.isAdminUserEnhanced(context.Background(), signIn.UserPrincipalName)
-isService := s.isServiceUserEnhanced(context.Background(), signIn.UserPrincipalName)
+isAdmin := s.isAdminUserEnhanced(ctx, signIn.UserPrincipalName)
+isService := s.isServiceUserEnhanced(ctx, signIn.UserPrincipalName)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff456f4 and 4c2e98e.

📒 Files selected for processing (7)
  • client/intune_devices.go (1 hunks)
  • client/intune_registry.go (1 hunks)
  • client/intune_sessions_direct.go (1 hunks)
  • client/user_roles.go (1 hunks)
  • cmd/list-intune-compliance.go (1 hunks)
  • cmd/list-intune-devices.go (1 hunks)
  • models/azure/intune.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • client/intune_devices.go
  • client/intune_registry.go
🧰 Additional context used
🧬 Code Graph Analysis (1)
client/intune_sessions_direct.go (5)
client/query/params.go (4)
  • GraphParams (109-120)
  • Top (42-42)
  • Format (30-30)
  • Select (37-37)
client/client.go (2)
  • AzureResult (120-123)
  • SignInEvent (40-61)
models/azure/intune_sessions.go (8)
  • DeviceSessionData (23-30)
  • ActiveSession (42-54)
  • LoggedOnUser (57-68)
  • SuspiciousActivity (82-90)
  • SessionData (33-39)
  • SessionSecurityInfo (71-79)
  • SessionDataSummary (93-101)
  • CredentialExposure (143-152)
constants/misc.go (3)
  • GraphApiVersion (43-43)
  • DisplayName (29-29)
  • Description (30-30)
models/azure/intune.go (3)
  • IntuneDevice (36-86)
  • DeviceInfo (153-159)
  • SecurityIndicators (171-176)
🔇 Additional comments (10)
cmd/list-intune-devices.go (2)

35-39: Good error handling implementation!

The error handling for client creation has been properly implemented, addressing the previous review comment.


57-72: Clean implementation with proper error handling!

The function correctly handles the channel iteration and the previously flagged unused count variable has been removed.

cmd/list-intune-compliance.go (3)

34-39: Good implementation avoiding global variables!

The flags are properly defined without using global variables, addressing the previous review comment.


63-66: Excellent use of local flag retrieval!

The implementation correctly retrieves flag values locally, avoiding global state issues.


173-185: Correct control flow implementation!

The function properly returns after sending the fallback compliance data, addressing the previous review comment about incorrect use of continue.

models/azure/intune.go (2)

8-33: Excellent type safety improvement!

The ChromeOSDeviceInfo is now properly typed as a slice of the defined struct instead of []interface{}, addressing the previous review comment and improving type safety.

Also applies to: 68-68


254-261: Good security practice for sensitive data!

The ClientSecret field is properly excluded from JSON serialization with the json:"-" tag, and a warning comment has been added, addressing the previous security concern.

client/user_roles.go (3)

15-32: Good implementation of package-level admin role definitions

The extraction of admin role names to a package-level variable improves maintainability and addresses the previous review feedback effectively.


72-107: Well-structured admin detection with proper fallback

Excellent implementation with API-first approach and heuristic fallback. The function properly distinguishes between directory roles and groups using OData types.


210-237: Robust GUID validation implementation

Well-implemented GUID validation with proper format checking (8-4-4-4-12) and hexadecimal character validation.

Comment on lines 74 to 88
// Helper function to create client with proper error handling
func connectAndCreateClientWithError() (client.AzureClient, error) {
// This function should be implemented to return both client and error
// For now, we'll assume connectAndCreateClient() exists and wrap it
// In a real implementation, you'd modify the original function or create a new one
defer func() {
if r := recover(); r != nil {
// Convert panic to error if the original function panics
panic(fmt.Errorf("failed to create client: %v", r))
}
}()

azClient := connectAndCreateClient()
return azClient, nil
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix panic recovery logic

The panic recovery converts the panic to another panic instead of returning an error, defeating the purpose of recovery.

-defer func() {
-    if r := recover(); r != nil {
-        // Convert panic to error if the original function panics
-        panic(fmt.Errorf("failed to create client: %v", r))
-    }
-}()
-
-azClient := connectAndCreateClient()
-return azClient, nil
+var azClient client.AzureClient
+var err error
+
+defer func() {
+    if r := recover(); r != nil {
+        err = fmt.Errorf("failed to create client: %v", r)
+    }
+}()
+
+azClient = connectAndCreateClient()
+return azClient, err
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Helper function to create client with proper error handling
func connectAndCreateClientWithError() (client.AzureClient, error) {
// This function should be implemented to return both client and error
// For now, we'll assume connectAndCreateClient() exists and wrap it
// In a real implementation, you'd modify the original function or create a new one
defer func() {
if r := recover(); r != nil {
// Convert panic to error if the original function panics
panic(fmt.Errorf("failed to create client: %v", r))
}
}()
azClient := connectAndCreateClient()
return azClient, nil
}
// Helper function to create client with proper error handling
func connectAndCreateClientWithError() (client.AzureClient, error) {
var azClient client.AzureClient
var err error
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("failed to create client: %v", r)
}
}()
azClient = connectAndCreateClient()
return azClient, err
}
🤖 Prompt for AI Agents
In cmd/list-intune-devices.go around lines 74 to 88, the panic recovery block
currently re-panics with an error instead of returning it, which defeats the
purpose of recovery. Modify the function to catch the panic and return it as an
error instead of panicking again. You can achieve this by using a named error
return variable and setting it inside the deferred function when a panic occurs,
then returning the client and error normally.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
client/intune_sessions_direct.go (1)

367-373: Potential integer overflow in getIdleTime function

The function casts duration.Hours() directly to int without bounds checking, which could potentially cause issues with very large durations.

Consider adding bounds checking or using a more robust time formatting approach:

func getIdleTime(logonTime time.Time) string {
	duration := time.Since(logonTime)
+	if duration < 0 {
+		duration = 0
+	}
	hours := int(duration.Hours())
+	if hours > 9999 {
+		hours = 9999
+	}
	minutes := int(duration.Minutes()) % 60
	seconds := int(duration.Seconds()) % 60
	return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c2e98e and d84286a.

📒 Files selected for processing (2)
  • client/intune_sessions_direct.go (1 hunks)
  • cmd/list-intune-devices.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/list-intune-devices.go
🔇 Additional comments (12)
client/intune_sessions_direct.go (12)

1-13: Package structure and imports look good

The imports are well-organized and include all necessary dependencies for the functionality.


15-20: Helper function follows established patterns

The setDefaultSessionParams function correctly follows the AzureHound pattern and sets appropriate defaults for sign-in logs.


22-89: Main collection function implements robust error handling

The CollectSessionDataDirectly function properly handles errors with a threshold-based approach and provides informative feedback. The context propagation to processSignInLogsSimple correctly addresses the past review comment.


95-96: Good fix for OData injection vulnerability

The sanitization of userPrincipalName by escaping single quotes properly addresses the security concern raised in past reviews.


121-122: Consistent security fix applied

The same OData injection protection is correctly applied to deviceId parameter.


191-191: Context parameter correctly added to function signature

The function signature now includes the context.Context parameter as suggested in past reviews, enabling proper context propagation.


226-228: Context propagation implemented correctly

The context is now properly passed to the enhanced role detection functions instead of using context.Background(), addressing the past review comment.


182-183: Function call updated with context parameter

The call to createDeviceSessionData now properly passes the context parameter, completing the fix for context propagation.


143-155: Excellent adherence to AzureHound patterns

The listSignInLogs function correctly follows the established AzureHound pattern by using getAzureObjectList and proper path construction.


273-284: Comprehensive suspicious activity detection

The risk detection logic properly identifies high-risk sign-ins and creates structured suspicious activity records with appropriate metadata.


288-324: Well-structured session data creation

The session data structure creation is comprehensive and includes all necessary security indicators, summaries, and device information.


334-340: Potential panic in getUsernameFromUPN function

The function splits the UPN but doesn't validate that the split produces at least one element before accessing parts[0].

Apply this fix to prevent potential index out of bounds:

func getUsernameFromUPN(upn string) string {
	if upn == "" {
		return "Unknown"
	}
	parts := strings.Split(upn, "@")
+	if len(parts) == 0 {
+		return "Unknown"
+	}
	return parts[0]
}

Likely an incorrect or invalid review comment.

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