Documentation
Go SDK
Official SDK for Go 1.21+
Installation
go get github.com/qodryx/sdk-goRequirements
- Go 1.21 or higher
Quick Start
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/qodryx/sdk-go"
)
func main() {
// Initialize the client
client := qodryx.NewClient(os.Getenv("QODRYX_API_KEY"))
ctx := context.Background()
// List projects
projects, err := client.Projects.List(ctx, nil)
if err != nil {
log.Fatal(err)
}
for _, project := range projects.Data {
fmt.Printf("%s: %s\n", project.Name, project.ID)
}
// Trigger a security scan
scan, err := client.Security.Scan(ctx, &qodryx.ScanOptions{
ProjectID: "proj_abc123",
Types: []string{"sast", "secrets", "dependencies"},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Scan started: %s\n", scan.ID)
}Configuration
package main
import (
"net/http"
"time"
"github.com/qodryx/sdk-go"
)
func main() {
// Basic configuration
client := qodryx.NewClient(os.Getenv("QODRYX_API_KEY"))
// With options
client := qodryx.NewClient(
os.Getenv("QODRYX_API_KEY"),
qodryx.WithBaseURL("https://api.qodryx.com"),
qodryx.WithTimeout(60*time.Second),
qodryx.WithRetries(3),
qodryx.WithHTTPClient(&http.Client{
Timeout: 30 * time.Second,
}),
qodryx.WithHeaders(map[string]string{
"X-Custom-Header": "value",
}),
)
}API Reference
Projects
ctx := context.Background()
// List all projects
projects, err := client.Projects.List(ctx, &qodryx.ListOptions{
Page: 1,
PerPage: 20,
})
// Get a specific project
project, err := client.Projects.Get(ctx, "proj_abc123")
// Create a new project
newProject, err := client.Projects.Create(ctx, &qodryx.CreateProjectOptions{
Name: "my-app",
Repository: "github.com/user/my-app",
Description: "My awesome app",
})
// Update a project
updated, err := client.Projects.Update(ctx, "proj_abc123", &qodryx.UpdateProjectOptions{
Name: "new-name",
})
// Delete a project
err := client.Projects.Delete(ctx, "proj_abc123")Workflows
ctx := context.Background()
// Create and trigger a workflow
workflow, err := client.Workflows.Create(ctx, &qodryx.CreateWorkflowOptions{
ProjectID: "proj_abc123",
Prompt: "Add OAuth authentication with Google",
Config: &qodryx.WorkflowConfig{
AIProvider: "anthropic",
AutoDeploy: false,
},
})
// List workflows
workflows, err := client.Workflows.List(ctx, &qodryx.ListWorkflowsOptions{
ProjectID: "proj_abc123",
Status: "running",
})
// Get workflow status
status, err := client.Workflows.Get(ctx, "wf_xyz789")
// Get workflow logs
logs, err := client.Workflows.Logs(ctx, "wf_xyz789", &qodryx.LogsOptions{
Stage: "build",
})
// Cancel a workflow
err := client.Workflows.Cancel(ctx, "wf_xyz789")
// Wait for workflow completion
result, err := client.Workflows.WaitForCompletion(ctx, "wf_xyz789", &qodryx.WaitOptions{
Timeout: 5 * time.Minute,
PollInterval: 5 * time.Second,
})Security
ctx := context.Background()
// Trigger a security scan
scan, err := client.Security.Scan(ctx, &qodryx.ScanOptions{
ProjectID: "proj_abc123",
Types: []string{"sast", "secrets", "dependencies"},
Branch: "main",
})
// Get scan results
results, err := client.Security.Results(ctx, "scan_abc123")
// List all findings
findings, err := client.Security.Findings(ctx, &qodryx.FindingsOptions{
ProjectID: "proj_abc123",
Severity: []string{"critical", "high"},
Status: "open",
})
// Get specific finding
finding, err := client.Security.Finding(ctx, "finding_abc123")
// Auto-remediate a finding
remediation, err := client.Security.Remediate(ctx, "finding_abc123")
// Ignore a finding
err := client.Security.Ignore(ctx, "finding_abc123", &qodryx.IgnoreOptions{
Reason: "False positive - test file",
})Deployments
ctx := context.Background()
// Trigger a deployment
deployment, err := client.Deployments.Create(ctx, &qodryx.CreateDeploymentOptions{
ProjectID: "proj_abc123",
Environment: "production",
Provider: "vercel",
Branch: "main",
})
// Get deployment status
status, err := client.Deployments.Get(ctx, "deploy_abc123")
// List deployments
deployments, err := client.Deployments.List(ctx, &qodryx.ListDeploymentsOptions{
ProjectID: "proj_abc123",
Environment: "production",
})
// Rollback a deployment
err := client.Deployments.Rollback(ctx, "deploy_abc123")
// Get deployment logs
logs, err := client.Deployments.Logs(ctx, "deploy_abc123")Tests
ctx := context.Background()
// Generate tests for a file
tests, err := client.Tests.Generate(ctx, &qodryx.GenerateTestsOptions{
ProjectID: "proj_abc123",
FilePath: "pkg/auth/login.go",
Framework: "testing",
})
// Run tests
results, err := client.Tests.Run(ctx, &qodryx.RunTestsOptions{
ProjectID: "proj_abc123",
Coverage: true,
})
// Get test coverage
coverage, err := client.Tests.Coverage(ctx, "proj_abc123")Error Handling
import (
"errors"
"github.com/qodryx/sdk-go"
)
ctx := context.Background()
scan, err := client.Security.Scan(ctx, &qodryx.ScanOptions{
ProjectID: "proj_abc123",
})
if err != nil {
var apiErr *qodryx.APIError
if errors.As(err, &apiErr) {
switch apiErr.Code {
case qodryx.ErrAuthentication:
log.Println("Invalid API key")
case qodryx.ErrRateLimit:
log.Printf("Rate limit exceeded, retry after %d seconds", apiErr.RetryAfter)
case qodryx.ErrNotFound:
log.Println("Project not found")
case qodryx.ErrValidation:
log.Printf("Validation error: %v", apiErr.Errors)
default:
log.Printf("API error: %s - %s", apiErr.Code, apiErr.Message)
}
return
}
log.Fatal(err)
}Context and Cancellation
import (
"context"
"time"
)
// With timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
projects, err := client.Projects.List(ctx, nil)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
log.Println("Request timed out")
return
}
log.Fatal(err)
}
// With cancellation
ctx, cancel := context.WithCancel(context.Background())
go func() {
// Cancel after some condition
time.Sleep(10 * time.Second)
cancel()
}()
result, err := client.Workflows.WaitForCompletion(ctx, "wf_xyz789", nil)
if errors.Is(err, context.Canceled) {
log.Println("Operation was cancelled")
}Pagination
ctx := context.Background()
// Manual pagination
page := 1
for {
projects, err := client.Projects.List(ctx, &qodryx.ListOptions{
Page: page,
PerPage: 50,
})
if err != nil {
log.Fatal(err)
}
for _, project := range projects.Data {
fmt.Println(project.Name)
}
if page >= projects.Meta.TotalPages {
break
}
page++
}
// Using iterator
iter := client.Projects.ListAll(ctx)
for iter.Next() {
project := iter.Current()
fmt.Println(project.Name)
}
if err := iter.Err(); err != nil {
log.Fatal(err)
}Webhooks
package main
import (
"io"
"log"
"net/http"
"github.com/qodryx/sdk-go/webhook"
)
func main() {
secret := os.Getenv("WEBHOOK_SECRET")
http.HandleFunc("/webhooks/qodryx", func(w http.ResponseWriter, r *http.Request) {
signature := r.Header.Get("X-Qodryx-Signature")
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Bad request", http.StatusBadRequest)
return
}
// Verify signature
if !webhook.Verify(body, signature, secret) {
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
// Parse event
event, err := webhook.Parse(body)
if err != nil {
http.Error(w, "Invalid payload", http.StatusBadRequest)
return
}
switch event.Type {
case webhook.WorkflowCompleted:
data := event.Data.(*webhook.WorkflowCompletedData)
log.Printf("Workflow completed: %s", data.WorkflowID)
case webhook.SecurityFindingCreated:
data := event.Data.(*webhook.SecurityFindingData)
log.Printf("New vulnerability: %s", data.Severity)
}
w.WriteHeader(http.StatusOK)
})
log.Fatal(http.ListenAndServe(":8080", nil))
}Concurrency
import (
"context"
"sync"
"golang.org/x/sync/errgroup"
)
ctx := context.Background()
// Scan multiple projects concurrently
projectIDs := []string{"proj_1", "proj_2", "proj_3"}
g, ctx := errgroup.WithContext(ctx)
results := make([]*qodryx.ScanResult, len(projectIDs))
var mu sync.Mutex
for i, id := range projectIDs {
i, id := i, id // Capture loop variables
g.Go(func() error {
scan, err := client.Security.Scan(ctx, &qodryx.ScanOptions{
ProjectID: id,
})
if err != nil {
return err
}
mu.Lock()
results[i] = scan
mu.Unlock()
return nil
})
}
if err := g.Wait(); err != nil {
log.Fatal(err)
}
for _, result := range results {
fmt.Printf("Scan started: %s\n", result.ID)
}Complete Example
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/qodryx/sdk-go"
)
func runSecurityCheck(projectID string) error {
client := qodryx.NewClient(os.Getenv("QODRYX_API_KEY"))
ctx := context.Background()
fmt.Println("Starting security scan...")
// Trigger scan
scan, err := client.Security.Scan(ctx, &qodryx.ScanOptions{
ProjectID: projectID,
Types: []string{"sast", "secrets", "dependencies"},
})
if err != nil {
return fmt.Errorf("failed to start scan: %w", err)
}
fmt.Printf("Scan started: %s\n", scan.ID)
// Wait for completion
for {
results, err := client.Security.Results(ctx, scan.ID)
if err != nil {
return fmt.Errorf("failed to get results: %w", err)
}
switch results.Status {
case "completed":
fmt.Println("Scan completed!")
// Check for critical findings
var critical []qodryx.Finding
for _, f := range results.Findings {
if f.Severity == "critical" {
critical = append(critical, f)
}
}
if len(critical) > 0 {
fmt.Printf("❌ Found %d critical vulnerabilities:\n", len(critical))
for _, f := range critical {
fmt.Printf(" - %s (%s:%d)\n", f.Title, f.File, f.Line)
}
return fmt.Errorf("critical vulnerabilities found")
}
fmt.Println("✅ No critical vulnerabilities found")
return nil
case "failed":
return fmt.Errorf("scan failed")
}
fmt.Printf("Scan in progress... (%s)\n", results.Status)
time.Sleep(5 * time.Second)
}
}
func main() {
projectID := os.Getenv("QODRYX_PROJECT")
if len(os.Args) > 1 {
projectID = os.Args[1]
}
if projectID == "" {
log.Fatal("Usage: go run main.go <project_id>")
}
if err := runSecurityCheck(projectID); err != nil {
log.Fatal(err)
}
}