Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
SARIF viewer to view the results of static analysis tools in the IDE.
The Sarif comes from GitHub Advanced Security (GHAS) or from the local file system.

You must provide in the settings a personal access token (PAT) to access the GitHub API with as least the following scopes:
- Pull request read
- Code scanning read
- Metadata read
**Authentication:**
- **GitHub.com**: Authentication is handled automatically through IntelliJ's built-in GitHub integration. Go to Settings > Version Control > GitHub to configure authentication.
- **GitHub Enterprise Server**: You must provide a personal access token (PAT) to access the GitHub API with at least the following scopes:
- Pull request read
- Code scanning read
- Metadata read


<!-- Plugin description end -->
Expand All @@ -27,14 +29,16 @@ You must provide in the settings a personal access token (PAT) to access the Git

## Configuration

You must provide a personal access token (PAT) to access the GitHub API with as least the following scopes:
- Pull request read
- Code scanning read
- Metadata read
**For GitHub.com:**
- No manual configuration required! Authentication is handled automatically through IntelliJ's built-in GitHub integration.
- If you're not already authenticated, go to `Settings > Version Control > GitHub` to configure authentication.

And add it to the plugin configuration via `Settings > Tools > Sarif Viewer`

If you are using GHES, you must also provide the URL and the corresponding token of your GHES instance.
**For GitHub Enterprise Server (GHES):**
- You must provide a personal access token (PAT) to access the GitHub API with at least the following scopes:
- Pull request read
- Code scanning read
- Metadata read
- Add your GHES hostname and PAT to the plugin configuration via `Settings > Tools > Sarif Viewer`

<img alt="docs/settings.png" width="640" src="docs/settings.png"/>

Expand Down
71 changes: 71 additions & 0 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Manual Testing Guide for GitHub Authentication

## Overview
This guide provides steps to manually test the new GitHub authentication mechanism.

## Test Cases

### 1. GitHub.com Authentication
**Expected Behavior**: The plugin should use IntelliJ's built-in GitHub authentication automatically.

**Steps**:
1. Open IntelliJ IDEA
2. Open a project that's connected to a GitHub.com repository
3. Open the SARIF viewer tool window
4. The plugin should automatically attempt to authenticate using IntelliJ's GitHub integration
5. If not authenticated, you should see a dialog prompting you to configure GitHub authentication

**Verification**:
- No manual PAT configuration should be required for GitHub.com
- Error messages should direct users to IntelliJ's GitHub settings

### 2. GitHub Enterprise Server (GHES) Authentication
**Expected Behavior**: The plugin should continue to use PAT-based authentication for GHES instances.

**Steps**:
1. Configure a GHES hostname in Settings > Tools > SARIF Viewer
2. Add a valid PAT for the GHES instance
3. Open a project connected to the GHES repository
4. Open the SARIF viewer tool window
5. The plugin should use the configured PAT

**Verification**:
- PAT configuration should still be required for GHES
- Error messages should indicate missing PAT for GHES instances

### 3. Settings UI
**Expected Behavior**: The settings UI should reflect the new authentication approach.

**Steps**:
1. Go to Settings > Tools > SARIF Viewer
2. Check the GitHub.com section
3. Check the GHES section

**Verification**:
- GitHub.com section should show information about automatic authentication
- GHES section should still allow PAT configuration
- No GitHub.com PAT field should be present

## Error Scenarios

### 1. Missing GitHub.com Authentication
**Steps**: Use plugin with GitHub.com repo when not authenticated in IntelliJ
**Expected**: Clear error message directing to IntelliJ GitHub settings

### 2. Missing GHES PAT
**Steps**: Use plugin with GHES repo without configuring PAT
**Expected**: Clear error message about missing PAT for GHES

### 3. Invalid GHES PAT
**Steps**: Configure invalid PAT for GHES
**Expected**: Authentication failure with appropriate error message

## Backward Compatibility

### 1. Existing PAT Configurations
**Steps**: Test with existing plugin installations that have GitHub.com PATs configured
**Expected**: Plugin should work without requiring reconfiguration

### 2. GHES Workflows
**Steps**: Test existing GHES workflows
**Expected**: No change in behavior for GHES instances
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,20 @@ import javax.swing.JToggleButton

class SettingComponent {
private var myMainPanel: JPanel? = null
private var ghTokenTextField: JTextField =JBTextField()
private var ghTokenPasswordField: JTextField = JBPasswordField()
private val ghesHostnameText = JBTextField()
private var ghesTokenTextField: JTextField = JBTextField()
private var ghesTokenPasswordField: JTextField = JBPasswordField()
private val toggleButton = JToggleButton("Show/Hide PAT")
private val toggleButton = JToggleButton("Show/Hide GHES PAT")

private var isGhTokenVisible: Boolean = false
private var isGhesTokenVisible: Boolean = false

init {

ghTokenTextField.isVisible = isGhTokenVisible
ghesTokenTextField.isVisible = isGhTokenVisible
ghesTokenTextField.isVisible = isGhesTokenVisible
myMainPanel = FormBuilder.createFormBuilder()
.addComponent(JBLabel("GitHub.com PAT "))
.addComponent(ghTokenTextField)
.addComponent(ghTokenPasswordField)
.addComponent(JBLabel("GitHub.com Authentication"))
.addComponent(JBLabel("Authentication is handled automatically through IntelliJ's GitHub integration."))
.addComponent(JBLabel("Go to Settings > Version Control > GitHub to configure authentication."))
.addSeparator(48)
.addComponent(JBLabel("GHES Hostname "))
.addComponent(ghesHostnameText)
Expand All @@ -43,20 +40,12 @@ class SettingComponent {
.panel

toggleButton.addActionListener {
isGhTokenVisible = !isGhTokenVisible
if (isGhTokenVisible) {
ghTokenTextField.text = ghTokenPasswordField.text
ghTokenTextField.isVisible = true
ghTokenPasswordField.isVisible = false

isGhesTokenVisible = !isGhesTokenVisible
if (isGhesTokenVisible) {
ghesTokenTextField.text = ghesTokenPasswordField.text
ghesTokenTextField.isVisible = true
ghesTokenPasswordField.isVisible = false
} else {
ghTokenPasswordField.text = ghTokenTextField.text
ghTokenTextField.isVisible = false
ghTokenPasswordField.isVisible = true

ghesTokenPasswordField.text = ghesTokenTextField.text
ghesTokenTextField.isVisible = false
ghesTokenPasswordField.isVisible = true
Expand All @@ -73,31 +62,27 @@ class SettingComponent {

fun getPreferredFocusedComponent(): JComponent {
return if (toggleButton.isSelected) {
ghTokenTextField
ghesTokenTextField
} else {
ghTokenPasswordField
ghesTokenPasswordField
}
}

fun getGhTokenText(): String {
return if (isGhTokenVisible) {
ghTokenTextField.text
} else {
ghTokenPasswordField.text
}
// Return empty string for GitHub.com PAT since it's no longer used
return ""
}

fun setGhTokenText(newText: String) {
ghTokenTextField.text = newText
ghTokenPasswordField.text = newText
// No-op since GitHub.com PAT is no longer used
}

fun getGhesHostnameText(): String {
return ghesHostnameText.text
}

fun getGhesTokenText(): String {
return if (isGhTokenVisible) {
return if (isGhesTokenVisible) {
ghesTokenTextField.text
} else {
ghesTokenPasswordField.text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,20 @@ class Settings : Configurable, Configurable.NoScroll, Disposable {

override fun createComponent(): JComponent {
mySettingsComponent = SettingComponent()
mySettingsComponent!!.setGhTokenText(SettingsState.instance.state.pat)
mySettingsComponent!!.setGhesHostnameText(SettingsState.instance.state.ghesHostname)
mySettingsComponent!!.setGhesTokenText(SettingsState.instance.state.ghesPat)
return mySettingsComponent!!.getPanel()
}

override fun isModified(): Boolean =
listOf(
mySettingsComponent!!.getGhTokenText() != SettingsState.instance.state.pat,
mySettingsComponent!!.getGhesHostnameText() != SettingsState.instance.state.ghesHostname,
mySettingsComponent!!.getGhesTokenText() != SettingsState.instance.state.ghesPat,
).any()

override fun apply() {
val settings: SettingsState = SettingsState.instance
settings.state.pat = mySettingsComponent!!.getGhTokenText()
// Keep the PAT for backward compatibility but don't require user input for GitHub.com
settings.state.ghesHostname = mySettingsComponent!!.getGhesHostnameText()
settings.state.ghesPat = mySettingsComponent!!.getGhesTokenText()

Expand All @@ -48,7 +46,6 @@ class Settings : Configurable, Configurable.NoScroll, Disposable {
}

override fun reset() {
mySettingsComponent?.setGhTokenText(SettingsState.instance.state.pat)
mySettingsComponent?.setGhesHostnameText(SettingsState.instance.state.ghesHostname)
mySettingsComponent?.setGhesTokenText(SettingsState.instance.state.ghesPat)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package com.github.adrienpessu.sarifviewer.services

import com.github.adrienpessu.sarifviewer.utils.GitHubInstance
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URI

@Service(Service.Level.PROJECT)
class GitHubAuthenticationService(private val project: Project) {

fun getAuthenticatedToken(gitHubInstance: GitHubInstance): String? {
return when {
gitHubInstance.useBuiltInAuth -> {
getGitHubDotComToken()
}
else -> {
// For GHES instances, use the configured token
if (gitHubInstance.token.isNotEmpty()) {
gitHubInstance.token
} else {
null
}
}
}
}

private fun getGitHubDotComToken(): String? {
// Try to get token from git credentials
return try {
getTokenFromGitCredentials()
} catch (e: Exception) {
// If git credentials don't work, prompt for authentication
promptForGitHubAuth()
}
}

private fun getTokenFromGitCredentials(): String? {
// This would typically use git credential helper
// For now, return null to trigger authentication prompt
return null
}

private fun promptForGitHubAuth(): String? {
// Show dialog to user explaining they need to authenticate
val result = Messages.showOkCancelDialog(
project,
"GitHub authentication is required to access the API.\n\n" +
"Please ensure you're logged into GitHub in IntelliJ IDEA.\n" +
"Go to Settings > Version Control > GitHub to configure authentication.",
"GitHub Authentication Required",
"Open Settings",
"Cancel",
Messages.getInformationIcon()
)

if (result == Messages.OK) {
// Open settings - this would typically open the GitHub settings page
// For now, we'll just return null and let the user configure manually
return null
}

return null
}

fun isGitHubDotComAuthenticated(): Boolean {
val token = getGitHubDotComToken()
return token != null && token.isNotEmpty()
}

fun testAuthentication(gitHubInstance: GitHubInstance): Boolean {
val token = getAuthenticatedToken(gitHubInstance)
if (token == null || token.isEmpty()) {
return false
}

return try {
val connection = URI("${gitHubInstance.apiBase}/user")
.toURL()
.openConnection() as HttpURLConnection

connection.apply {
requestMethod = "GET"
setRequestProperty("Authorization", "Bearer $token")
setRequestProperty("Accept", "application/vnd.github.v3+json")
}

connection.responseCode == 200
} catch (e: IOException) {
false
}
}
}
Loading
Loading