Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api support for repos #1887

Merged
merged 5 commits into from
Feb 24, 2025
Merged

api support for repos #1887

merged 5 commits into from
Feb 24, 2025

Conversation

motatoes
Copy link
Contributor

@motatoes motatoes commented Feb 24, 2025

Summary by CodeRabbit

  • New Features

    • Redesigned the API interface to streamline repository management and GitHub integration. Legacy endpoints for handling projects, activities, and runs have been retired, making way for a focused set of features.
    • Introduced endpoints for listing repositories and linking GitHub installations to organizations.
  • Chores

    • Enhanced API request authentication by enforcing required headers.
    • Applied a database update and expanded repository details to support version control system information.

Copy link
Contributor

coderabbitai bot commented Feb 24, 2025

Warning

Rate limit exceeded

@motatoes has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 8 minutes and 26 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 15bf418 and b81a186.

📒 Files selected for processing (4)
  • backend/controllers/github_api.go (1 hunks)
  • backend/controllers/repos.go (1 hunks)
  • backend/middleware/headers.go (1 hunks)
  • backend/models/orgs.go (3 hunks)

Walkthrough

This pull request restructures the backend API endpoints. It removes the granular project, activity, and run routes and introduces a conditional API group that provides endpoints for listing repositories and linking GitHub installations when enabled. New middleware is added to validate required headers, and additional JWT context keys are defined. A migration modifies the repos table by adding a VCS column, and the Repo model is updated with a new VCS field and JSON mapping method.

Changes

File(s) Change Summary
backend/bootstrap/main.go Removed projects, activity, and runs API groups; added a conditional /api group with sub-groups for /api/repos and /api/github/link using HeadersApiAuth.
backend/controllers/{github_api.go, repos.go} Added new API endpoints: LinkGithubInstallationToOrgApi for linking GitHub installations and ListReposApi for retrieving organization repositories.
backend/middleware/{headers.go, jwt.go} Introduced HeadersApiAuth middleware for validating headers; added JWT context constants (ORGANISATION_SOURCE_KEY, USER_ID_KEY) for enhanced context.
backend/migrations/…/20250224152926.sql Added a SQL migration to update the repos table by introducing a vcs column of type text with a default value of 'github'.
backend/models/orgs.go Updated the Repo struct with a new VCS field and added a MapToJsonStruct method to provide a structured JSON representation.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant M as Middleware (HeadersApiAuth)
    participant G as GitHub Controller
    participant DB as Database
    participant R as Response

    C->>M: Send request to /api/github/link
    M->>G: Pass validated request
    G->>DB: Query organization and installation link
    DB-->>G: Return organization/link data
    G->>DB: Create or verify GitHub installation link
    G->>R: Return status (200/400/500)
sequenceDiagram
    participant C as Client
    participant M as Middleware (HeadersApiAuth)
    participant R as Repo Controller
    participant DB as Database

    C->>M: Send request to /api/repos
    M->>R: Forward validated request
    R->>DB: Query organization and repository list
    DB-->>R: Return associated repositories
    R->>C: Respond with JSON list (200)

Possibly related PRs

  • publish ai summaries #1864: Involved integration of GitHub functionalities with the API structure; directly related to the introduction of githubApiGroup and GitHub linking endpoint.
  • feat/internal apis for users #1885: Modified the API bootstrap process to introduce internal endpoints, aligning with the restructuring of API groups in this PR.

Poem

In fields of code where changes hop,
I nibble bytes with each new crop.
APIs bloom with a fresh new sight,
GitHub links and repos alight.
Middleware guards like a vigilant guard,
As I skip along, forever on my codeward! 🐇


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

PR Summary

This pull request introduces middleware for header validation, modifies JWT middleware, and updates the database schema to support multiple VCS types.

  • Added HeadersApiAuth middleware in backend/middleware/headers.go to validate specific headers and set context parameters.
  • Introduced ORGANISATION_SOURCE_KEY and USER_ID_KEY constants in backend/middleware/jwt.go for enhanced context management.
  • Added a new vcs column to the repos table in backend/migrations/20250224152926.sql to support multiple VCS types.
  • Updated backend/models/orgs.go to include a VCS field in the Repo struct and a MapToJsonStruct method for JSON serialization.

💡 (3/5) Reply to the bot's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!

5 file(s) reviewed, 1 comment(s)
Edit PR Review Bot Settings | Greptile

return struct {
Id uint `json:"id"`
Name string `json:"name"`
RepoFullName string `json:"directory"`
Copy link
Contributor

Choose a reason for hiding this comment

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

syntax: RepoFullName should map to repo_full_name

Copy link
Contributor

@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: 5

🧹 Nitpick comments (4)
backend/controllers/repos.go (1)

21-22: Improve error message

The error message could be more descriptive by including the organization source.

-			c.String(http.StatusNotFound, "Could not find organisation: "+organisationId)
+			c.String(http.StatusNotFound, "Could not find organisation with ID "+organisationId+" and source "+organisationSource)
backend/controllers/github_api.go (2)

46-52: Add context to database operation.

The database operation could benefit from context propagation for better request lifecycle management.

Add context to the database operation:

-link, err := models.DB.GetGithubAppInstallationLink(installationId)
+link, err := models.DB.GetGithubAppInstallationLink(c.Request.Context(), installationId)

66-71: Add context to database operation and improve error handling.

Similar to the previous comment, this database operation could benefit from context propagation. Also, the error response could be more specific.

Add context and improve error handling:

-_, err = models.DB.CreateGithubInstallationLink(&org, installationId)
+_, err = models.DB.CreateGithubInstallationLink(c.Request.Context(), &org, installationId)
 if err != nil {
   log.Printf("failed to create installation link: %v", err)
-  c.JSON(http.StatusInternalServerError, gin.H{"status": "failed to create installation link"})
+  c.JSON(http.StatusInternalServerError, gin.H{"status": "Failed to create installation link. Please try again later."})
   return
 }
backend/bootstrap/main.go (1)

217-226: Consider adding API version prefix.

The new API endpoints are added under /api without version prefix. This could make future API versioning more difficult.

Consider adding API version prefix:

 if enableApi := os.Getenv("DIGGER_ENABLE_API_ENDPOINTS"); enableApi == "true" {
-  apiGroup := r.Group("/api")
+  apiGroup := r.Group("/api/v1")
   apiGroup.Use(middleware.HeadersApiAuth())

   reposApiGroup := apiGroup.Group("/repos")
   reposApiGroup.GET("/", controllers.ListReposApi)

   githubApiGroup := apiGroup.Group("/github")
   githubApiGroup.POST("/link", controllers.LinkGithubInstallationToOrgApi)
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f5f7f58 and 731c2c9.

⛔ Files ignored due to path filters (1)
  • backend/migrations/atlas.sum is excluded by !**/*.sum
📒 Files selected for processing (7)
  • backend/bootstrap/main.go (1 hunks)
  • backend/controllers/github_api.go (1 hunks)
  • backend/controllers/repos.go (1 hunks)
  • backend/middleware/headers.go (1 hunks)
  • backend/middleware/jwt.go (1 hunks)
  • backend/migrations/20250224152926.sql (1 hunks)
  • backend/models/orgs.go (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • backend/migrations/20250224152926.sql
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Build
  • GitHub Check: Build
  • GitHub Check: Build
🔇 Additional comments (5)
backend/middleware/jwt.go (1)

311-312: LGTM!

The new constants follow the existing naming pattern and are used consistently across the codebase.

backend/middleware/headers.go (1)

8-35: LGTM!

The middleware implementation is clean and follows consistent error handling patterns with clear error messages.

backend/models/orgs.go (1)

128-147: LGTM!

The MapToJsonStruct method follows the established pattern and provides a consistent JSON representation of the Repo entity.

backend/controllers/repos.go (1)

12-48: LGTM!

The implementation is well-structured with proper error handling and efficient database queries using joins and ordering.

backend/bootstrap/main.go (1)

217-226:

❓ Verification inconclusive

Verify the security implications of the new API endpoints.

The new API endpoints are protected by HeadersApiAuth middleware, but we should verify its security measures.

Let's check the implementation of the middleware:


🏁 Script executed:

#!/bin/bash
# Description: Check the implementation of HeadersApiAuth middleware
# and any security-related configurations.

# Check middleware implementation
rg -A 10 "func HeadersApiAuth" backend/middleware/

# Check for any security-related configurations
rg -g '*.go' "DIGGER_ENABLE_API_ENDPOINTS|HeadersApiAuth"

Length of output: 1035


Security Validation for New API Endpoints

The new API endpoints are guarded by the HeadersApiAuth middleware. Our verification shows that the middleware checks for the presence of the DIGGER_ORG_ID header (while also extracting DIGGER_ORG_SOURCE and DIGGER_USER_ID), and returns a bad request if DIGGER_ORG_ID is missing. Although this provides basic protection, please verify that merely checking for non-empty header values meets our security requirements. In particular, consider whether:

  • The minimal header presence check is sufficient to prevent spoofed requests.
  • Additional validations (e.g., verifying DIGGER_USER_ID or enforcing robust authentication tokens) should be implemented.
  • Any further security measures or documentation are warranted based on our threat model.

Comment on lines 36 to 37
return
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unnecessary return and add c.Next()

The return statement is unnecessary here, and c.Next() should be called to continue the middleware chain.

-		return
+		c.Next()
📝 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
return
}
c.Next()
}

return struct {
Id uint `json:"id"`
Name string `json:"name"`
RepoFullName string `json:"directory"`
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect JSON field mapping

The RepoFullName field is incorrectly mapped to "directory" in the JSON output. This seems to be a copy-paste error.

-		RepoFullName     string `json:"directory"`
+		RepoFullName     string `json:"repo_full_name"`
📝 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
RepoFullName string `json:"directory"`
RepoFullName string `json:"repo_full_name"`

Comment on lines 49 to 52
if err != nil {
c.String(http.StatusInternalServerError, "Unknown error occurred while marshalling response")
return
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove undefined error check

This error check is using an undefined error variable. The marshalling operation doesn't return an error, so this check is unnecessary.

-	if err != nil {
-		c.String(http.StatusInternalServerError, "Unknown error occurred while marshalling response")
-		return
-	}
📝 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
if err != nil {
c.String(http.StatusInternalServerError, "Unknown error occurred while marshalling response")
return
}

Comment on lines 21 to 24
if err != nil {
log.Printf("Error binding JSON: %v", err)
return
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error response for JSON binding failure.

The function returns without sending an error response when JSON binding fails. This could leave clients waiting for a response.

Add an error response:

 err := c.BindJSON(&request)
 if err != nil {
   log.Printf("Error binding JSON: %v", err)
+  c.JSON(http.StatusBadRequest, gin.H{"status": "Invalid request format"})
   return
 }
📝 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
if err != nil {
log.Printf("Error binding JSON: %v", err)
return
}
if err != nil {
log.Printf("Error binding JSON: %v", err)
c.JSON(http.StatusBadRequest, gin.H{"status": "Invalid request format"})
return
}

Comment on lines 31 to 37
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
log.Printf("could not find organisation: %v", err)
c.JSON(http.StatusNotFound, gin.H{"status": "Could not find organisation: " + organisationId})
}
return
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve error handling for database query.

The function returns without sending an error response for non-"record not found" errors. Also, the error log and response could be more descriptive.

Add proper error handling:

 err = models.DB.GormDB.Where("external_id = ? AND external_source = ?", organisationId, organisationSource).First(&org).Error
 if err != nil {
   if errors.Is(err, gorm.ErrRecordNotFound) {
     log.Printf("could not find organisation: %v", err)
     c.JSON(http.StatusNotFound, gin.H{"status": "Could not find organisation: " + organisationId})
+  } else {
+    log.Printf("database error while finding organisation: %v", err)
+    c.JSON(http.StatusInternalServerError, gin.H{"status": "Internal server error"})
   }
   return
 }
📝 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
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
log.Printf("could not find organisation: %v", err)
c.JSON(http.StatusNotFound, gin.H{"status": "Could not find organisation: " + organisationId})
}
return
}
err = models.DB.GormDB.Where("external_id = ? AND external_source = ?", organisationId, organisationSource).First(&org).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
log.Printf("could not find organisation: %v", err)
c.JSON(http.StatusNotFound, gin.H{"status": "Could not find organisation: " + organisationId})
} else {
log.Printf("database error while finding organisation: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{"status": "Internal server error"})
}
return
}

Copy link
Contributor

@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: 1

🧹 Nitpick comments (1)
backend/models/orgs.go (1)

140-140: Consider using Name instead of RepoName for consistency.

The Name field in the JSON output is mapped to RepoName, which might be confusing since the struct already has a Name field. Consider using the Name field directly for consistency.

Apply this diff to improve consistency:

-		Name:             r.RepoName,
+		Name:             r.Name,
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 731c2c9 and 15bf418.

📒 Files selected for processing (1)
  • backend/models/orgs.go (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Build
  • GitHub Check: Build
  • GitHub Check: Build
🔇 Additional comments (1)
backend/models/orgs.go (1)

23-23:

✅ Verification successful

Verify the DiggerVCSType type definition.

The DiggerVCSType type used in the VCS field is not defined in this file. Please ensure it's properly defined and imported.

Run the following script to locate the type definition:


🏁 Script executed:

#!/bin/bash
# Description: Search for the DiggerVCSType definition in the codebase.

# Search for type definition
ast-grep --pattern $'type DiggerVCSType'

# Search for any usage of DiggerVCSType
rg -A 5 $'DiggerVCSType'

Length of output: 4882


DiggerVCSType type verification complete

We confirmed that the DiggerVCSType type is correctly defined in backend/models/scheduler.go as a string alias—accompanied by its constants (e.g., DiggerVCSGithub, DiggerVCSGitlab). Since backend/models/orgs.go and backend/models/scheduler.go belong to the same package, no additional import changes are necessary. The default value ('github') in the VCS field correctly aligns with the defined constant, so no further action is needed.

RepoUrl: r.RepoUrl,
VCS: string(r.VCS),
OrganisationID: r.OrganisationID,
OrganisationName: r.Organisation.Name,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add nil check for Organisation field.

Accessing r.Organisation.Name could cause a panic if Organisation is nil. Add a nil check to handle this case gracefully.

Apply this diff to add the nil check:

-		OrganisationName: r.Organisation.Name,
+		OrganisationName: func() string {
+			if r.Organisation == nil {
+				return ""
+			}
+			return r.Organisation.Name
+		}(),
📝 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
OrganisationName: r.Organisation.Name,
OrganisationName: func() string {
if r.Organisation == nil {
return ""
}
return r.Organisation.Name
}(),

@motatoes motatoes merged commit 889539f into develop Feb 24, 2025
12 checks passed
This was referenced Feb 25, 2025
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.

1 participant