Files
breakpilot-compliance/ai-compliance-sdk/internal/dsms/client.go
T
Benjamin Admin 66d30568e2
Build + Deploy / build-admin-compliance (push) Successful in 1m41s
Build + Deploy / build-backend-compliance (push) Successful in 14s
Build + Deploy / build-ai-sdk (push) Successful in 41s
Build + Deploy / build-developer-portal (push) Successful in 10s
Build + Deploy / build-tts (push) Successful in 10s
Build + Deploy / build-document-crawler (push) Successful in 10s
Build + Deploy / build-dsms-gateway (push) Successful in 10s
Build + Deploy / build-dsms-node (push) Successful in 11s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / loc-budget (push) Failing after 14s
CI / secret-scan (push) Has been skipped
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 2m31s
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / test-go (push) Successful in 48s
CI / test-python-backend (push) Failing after 1s
CI / test-python-document-crawler (push) Successful in 32s
CI / test-python-dsms-gateway (push) Successful in 25s
CI / validate-canonical-controls (push) Successful in 15s
Build + Deploy / trigger-orca (push) Successful in 2m23s
feat(dsms): Stufe 1 — Gap-Analyse Report wird in DSMS archiviert
- Go DSMS Client (internal/dsms/client.go): Archive() + Verify()
- Python DSMS Client (compliance/services/dsms_client.py): archive_to_dsms() + verify_dsms()
- Gap-Analyse AnalyzeProject() archiviert Report-JSON nach DSMS
- Response enthält dsms_cid wenn Archivierung erfolgreich
- Frontend: Grünes "Revisionssicher archiviert" Badge mit CID im GapDashboard
- DSMS Proxy Route (/api/sdk/v1/dsms/[...path]) für Verify-Abfragen

Stufe 2 (Evidence Upload → DSMS) und Stufe 3 (Version Chains) folgen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-11 23:39:26 +02:00

104 lines
2.5 KiB
Go

// Package dsms provides a client for archiving compliance artifacts to the
// DSMS gateway (IPFS-backed tamper-proof document storage).
package dsms
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"mime/multipart"
"net/http"
"os"
"time"
)
// ArchiveResult is the response from a successful DSMS archive operation.
type ArchiveResult struct {
CID string `json:"cid"`
Size int `json:"size"`
GatewayURL string `json:"gateway_url"`
}
var gatewayURL = getEnv("DSMS_GATEWAY_URL", "http://dsms-gateway:8082")
func getEnv(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}
// Archive stores content in DSMS and returns the CID.
// Non-critical: returns nil on failure (logs warning).
func Archive(content []byte, filename, documentType, documentID, version string) *ArchiveResult {
var buf bytes.Buffer
w := multipart.NewWriter(&buf)
part, err := w.CreateFormFile("file", filename)
if err != nil {
log.Printf("[dsms] multipart error: %v", err)
return nil
}
if _, err := part.Write(content); err != nil {
log.Printf("[dsms] write error: %v", err)
return nil
}
_ = w.WriteField("document_type", documentType)
_ = w.WriteField("document_id", documentID)
_ = w.WriteField("version", version)
_ = w.WriteField("language", "de")
w.Close()
client := &http.Client{Timeout: 60 * time.Second}
req, err := http.NewRequest("POST", gatewayURL+"/api/v1/documents", &buf)
if err != nil {
log.Printf("[dsms] request error: %v", err)
return nil
}
req.Header.Set("Content-Type", w.FormDataContentType())
req.Header.Set("Authorization", "Bearer system-backend")
resp, err := client.Do(req)
if err != nil {
log.Printf("[dsms] unavailable: %v", err)
return nil
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode != 200 {
log.Printf("[dsms] archive failed (%d): %s", resp.StatusCode, string(body[:min(len(body), 200)]))
return nil
}
var result ArchiveResult
if err := json.Unmarshal(body, &result); err != nil {
log.Printf("[dsms] parse error: %v", err)
return nil
}
log.Printf("[dsms] archived: %s → CID %s (%d bytes)", filename, result.CID, result.Size)
return &result
}
// Verify checks document integrity by CID.
func Verify(cid string) (bool, error) {
client := &http.Client{Timeout: 15 * time.Second}
resp, err := client.Get(fmt.Sprintf("%s/api/v1/verify/%s", gatewayURL, cid))
if err != nil {
return false, err
}
defer resp.Body.Close()
return resp.StatusCode == 200, nil
}
func min(a, b int) int {
if a < b {
return a
}
return b
}