Skip to content
Open
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
91 changes: 91 additions & 0 deletions backend/plugins/checkmarxone/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# CheckmarxOne Plugin

## Summary

This plugin collects security findings and vulnerabilities from [CheckmarxOne](https://checkmarx.com/checkmarx-one/) - a leading application security testing platform.

## Features

- Collect security findings/vulnerabilities from CheckmarxOne projects
- Track vulnerability severity, status, and remediation progress
- Support for multiple projects
- Integration with DevLake's security domain layer

## Requirements

- CheckmarxOne account and API access
- Server URL, Client ID, and Client Secret from CheckmarxOne

## Configuration

### Connection Setup

Create a connection to CheckmarxOne using the following fields:

- **Server URL**: The base URL of your CheckmarxOne instance (e.g., `https://checkmarx.mycompany.com`)
- **Client ID**: OAuth client ID for API access
- **Client Secret**: OAuth client secret for API access
- **Username**: (Optional) Username for authentication
- **Password**: (Optional) Password for authentication

### Scope Configuration

Select the CheckmarxOne projects you want to collect data from:

- **Project ID**: The unique identifier of the CheckmarxOne project

## Data Collection

The plugin collects the following data:

### Findings
- Finding ID and Name
- Severity Level (Critical, High, Medium, Low)
- Status (Open, Fixed, Suppressed)
- First Found and Last Found timestamps
- Finding Description
- Type of finding

## API Reference

### POST /connections
Create a new CheckmarxOne connection

### GET /connections
List all CheckmarxOne connections

### GET /connections/:connectionId
Get details of a specific connection

### PATCH /connections/:connectionId
Update a CheckmarxOne connection

### DELETE /connections/:connectionId
Delete a CheckmarxOne connection

## Troubleshooting

### Authentication Issues
- Verify Client ID and Client Secret are correct
- Ensure the API user has appropriate permissions in CheckmarxOne
- Check that the Server URL is accessible from the DevLake instance

### No Data Collected
- Verify that the project ID exists in CheckmarxOne
- Check that the API client has access to the specified project
- Review the logs for any API errors

## Development

To build and test the plugin locally:

```bash
cd backend/plugins/checkmarxone
go build
```

For standalone debugging:

```bash
./checkmarxone --connectionId=1 --projectId=myproject
```
109 changes: 109 additions & 0 deletions backend/plugins/checkmarxone/api/connection_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package api

import (
"net/http"
"strconv"
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
"github.com/apache/incubator-devlake/plugins/checkmarxone/models"
)

func PostConnections(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
connection := &models.CheckmarxoneConnection{}
err := input.GetBody(connection)
if err != nil {
return nil, errors.BadInput.Wrap(err, "invalid request body")
}

basicRes := input.Ctx.Value(plugin.CTX_KEY_BASIC_RES).(plugin.BasicRes)
if err := basicRes.GetDal().Create(connection); err != nil {
return nil, errors.Default.Wrap(err, "failed to create connection")
}

return &plugin.ApiResourceOutput{Body: connection, Status: http.StatusCreated}, nil
}

func ListConnections(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
var connections []models.CheckmarxoneConnection
basicRes := input.Ctx.Value(plugin.CTX_KEY_BASIC_RES).(plugin.BasicRes)

if err := basicRes.GetDal().All(&connections); err != nil {
return nil, errors.Default.Wrap(err, "failed to list connections")
}

return &plugin.ApiResourceOutput{Body: connections}, nil
}

func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
connectionId := input.Params["connectionId"]
connId, err := strconv.ParseUint(connectionId, 10, 64)
if err != nil {
return nil, errors.BadInput.New("invalid connection id")
}

connection := &models.CheckmarxoneConnection{}
basicRes := input.Ctx.Value(plugin.CTX_KEY_BASIC_RES).(plugin.BasicRes)

if err := basicRes.GetDal().First(connection, map[string]interface{}{"id": connId}); err != nil {
return nil, errors.NotFound.Wrap(err, "connection not found")
}

return &plugin.ApiResourceOutput{Body: connection}, nil
}

func PatchConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
connectionId := input.Params["connectionId"]
connId, err := strconv.ParseUint(connectionId, 10, 64)
if err != nil {
return nil, errors.BadInput.New("invalid connection id")
}

connection := &models.CheckmarxoneConnection{}
basicRes := input.Ctx.Value(plugin.CTX_KEY_BASIC_RES).(plugin.BasicRes)

err2 := input.GetBody(connection)
if err2 != nil {
return nil, errors.BadInput.Wrap(err2, "invalid request body")
}

connection.ID = connId
if err := basicRes.GetDal().Update(connection); err != nil {
return nil, errors.Default.Wrap(err, "failed to update connection")
}

return &plugin.ApiResourceOutput{Body: connection}, nil
}

func DeleteConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
connectionId := input.Params["connectionId"]
connId, err := strconv.ParseUint(connectionId, 10, 64)
if err != nil {
return nil, errors.BadInput.New("invalid connection id")
}

basicRes := input.Ctx.Value(plugin.CTX_KEY_BASIC_RES).(plugin.BasicRes)
connection := &models.CheckmarxoneConnection{}

if err := basicRes.GetDal().Delete(connection, map[string]interface{}{"id": connId}); err != nil {
return nil, errors.Default.Wrap(err, "failed to delete connection")
}

return &plugin.ApiResourceOutput{Status: http.StatusNoContent}, nil
}
19 changes: 19 additions & 0 deletions backend/plugins/checkmarxone/api/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package api

45 changes: 45 additions & 0 deletions backend/plugins/checkmarxone/checkmarxone.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main // must be main for plugin entry point

import (
"github.com/apache/incubator-devlake/core/runner"
"github.com/apache/incubator-devlake/plugins/checkmarxone/impl"
"github.com/spf13/cobra"
)

// PluginEntry is a variable exported for Framework to search and load
var PluginEntry impl.CheckmarxOne //nolint

// standalone mode for debugging
func main() {
cmd := &cobra.Command{Use: "checkmarxone"}
connectionId := cmd.Flags().Uint64P("connectionId", "c", 0, "checkmarxone connection id")
projectId := cmd.Flags().StringP("projectId", "p", "", "checkmarxone project id")
timeAfter := cmd.Flags().StringP("timeAfter", "a", "", "collect data that are created after specified time, ie 2006-01-02T15:04:05Z")
_ = cmd.MarkFlagRequired("connectionId")
_ = cmd.MarkFlagRequired("projectId")

cmd.Run = func(cmd *cobra.Command, args []string) {
runner.DirectRun(cmd, args, PluginEntry, map[string]interface{}{
"connectionId": *connectionId,
"projectId": *projectId,
}, *timeAfter)
}
runner.RunCmd(cmd)
}
Loading