f99010fae1
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Windows) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Has been cancelled
108 lines
3.4 KiB
Go
108 lines
3.4 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"github.com/danielgtaylor/huma/v2"
|
|
"go.kenn.io/agentsview/internal/db"
|
|
"go.kenn.io/agentsview/internal/service"
|
|
)
|
|
|
|
func (s *Server) registerSecretsRoutes() {
|
|
group := newRouteGroup(s.api, "/api/v1/secrets", "Secrets")
|
|
|
|
get(s, group, "", "List secret findings", s.humaListSecrets)
|
|
stream(s, group, http.MethodPost, "/scan", "Scan secrets", s.humaScanSecrets)
|
|
}
|
|
|
|
type secretListInput struct {
|
|
Project string `query:"project" doc:"Filter by project"`
|
|
Agent string `query:"agent" doc:"Filter by agent"`
|
|
DateFrom string `query:"date_from" format:"date" doc:"Filter start date"`
|
|
DateTo string `query:"date_to" format:"date" doc:"Filter end date"`
|
|
Rule string `query:"rule" doc:"Filter by secret rule"`
|
|
Confidence string `query:"confidence" doc:"Filter by confidence"`
|
|
Reveal bool `query:"reveal" doc:"Return unredacted matches for localhost callers"`
|
|
Limit int `query:"limit" minimum:"0" doc:"Maximum number of results"`
|
|
Cursor int `query:"cursor" minimum:"0" doc:"Pagination cursor"`
|
|
}
|
|
|
|
func (s *Server) humaListSecrets(
|
|
ctx context.Context,
|
|
in *secretListInput,
|
|
) (*jsonOutput[*service.SecretFindingList], error) {
|
|
if in.Reveal && !isLocalhostContext(ctx) {
|
|
return nil, apiError(http.StatusForbidden, "reveal is only permitted from localhost")
|
|
}
|
|
if err := validateDateFilterValues("", in.DateFrom, in.DateTo, ""); err != nil {
|
|
return nil, err
|
|
}
|
|
res, err := s.sessions.ListSecrets(ctx, service.SecretListFilter{
|
|
Project: in.Project,
|
|
Agent: in.Agent,
|
|
DateFrom: in.DateFrom,
|
|
DateTo: in.DateTo,
|
|
Rule: in.Rule,
|
|
Confidence: in.Confidence,
|
|
Reveal: in.Reveal,
|
|
Limit: in.Limit,
|
|
Cursor: in.Cursor,
|
|
})
|
|
if err != nil {
|
|
if handled := handleHumaContextError(err); handled != nil {
|
|
return nil, handled
|
|
}
|
|
if handled := handleHumaReadOnly(err); handled != nil {
|
|
return nil, handled
|
|
}
|
|
return nil, apiError(http.StatusInternalServerError, err.Error())
|
|
}
|
|
if res.Findings == nil {
|
|
res.Findings = []db.SecretFindingRow{}
|
|
}
|
|
return &jsonOutput[*service.SecretFindingList]{Body: res}, nil
|
|
}
|
|
|
|
type scanSecretsInput struct {
|
|
Backfill bool `query:"backfill" doc:"Backfill all matching sessions"`
|
|
Project string `query:"project" doc:"Filter by project"`
|
|
Agent string `query:"agent" doc:"Filter by agent"`
|
|
DateFrom string `query:"date_from" format:"date" doc:"Filter start date"`
|
|
DateTo string `query:"date_to" format:"date" doc:"Filter end date"`
|
|
}
|
|
|
|
func (s *Server) humaScanSecrets(
|
|
ctx context.Context,
|
|
in *scanSecretsInput,
|
|
) (*huma.StreamResponse, error) {
|
|
if err := validateDateFilterValues("", in.DateFrom, in.DateTo, ""); err != nil {
|
|
return nil, err
|
|
}
|
|
if s.engine == nil {
|
|
return nil, apiError(http.StatusNotImplemented, "not available in remote mode")
|
|
}
|
|
return &huma.StreamResponse{Body: func(hctx huma.Context) {
|
|
stream, ok := newHumaSSEStream(hctx)
|
|
if !ok {
|
|
writeHumaJSON(hctx, http.StatusInternalServerError,
|
|
apiErrorResponse{Message: "streaming not supported"})
|
|
return
|
|
}
|
|
summary, err := s.sessions.ScanSecrets(ctx, service.SecretScanInput{
|
|
Backfill: in.Backfill,
|
|
Project: in.Project,
|
|
Agent: in.Agent,
|
|
DateFrom: in.DateFrom,
|
|
DateTo: in.DateTo,
|
|
}, func(p service.SecretScanProgress) {
|
|
stream.SendJSON("progress", p)
|
|
})
|
|
if err != nil {
|
|
stream.SendJSON("error", map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
stream.SendJSON("summary", summary)
|
|
}}, nil
|
|
}
|