Skip to content

Commit b16ee7c

Browse files
committed
agents/sec-rev: final tweaks to agent code after review
Signed-off-by: Jacob Howard <[email protected]>
1 parent 8cb53f4 commit b16ee7c

File tree

4 files changed

+196
-184
lines changed

4 files changed

+196
-184
lines changed

agents/security-reviewer/Dockerfile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ RUN useradd --create-home --shell /bin/bash agent \
5454
&& install -d -o agent -g agent /workspace/input \
5555
&& install -d -o agent -g agent /workspace/output
5656

57-
# Copy the reviewer assets and report template.
57+
# Copy the reviewer entrypoint and assets.
5858
COPY --from=gobuilder /security-reviewer/build/reviewer /opt/security-reviewer/reviewer
5959
COPY --chown=agent:agent prompt-template.md /opt/security-reviewer/prompt-template.md
6060
COPY --chown=agent:agent report-template.md /opt/security-reviewer/report-template.md
@@ -67,17 +67,22 @@ WORKDIR /workspace
6767
ENTRYPOINT ["/opt/security-reviewer/reviewer"]
6868

6969

70-
# Lightweight image hosting the API proxy.
70+
# Use a debian image to host the proxy.
7171
FROM debian:trixie-slim AS proxy-image
7272

73+
# Install dependencies, including those needed for healthchecks.
7374
ENV DEBIAN_FRONTEND=noninteractive
7475
RUN apt-get update \
7576
&& apt-get install -y --no-install-recommends \
7677
ca-certificates \
7778
wget \
7879
&& rm -rf /var/lib/apt/lists/*
7980

81+
# Copy the proxy entrypoint.
8082
COPY --from=gobuilder /security-reviewer/build/proxy /opt/security-reviewer/proxy
8183

84+
# Expose the proxy's default port.
8285
EXPOSE 4000
86+
87+
# Set the proxy entrypoint.
8388
ENTRYPOINT ["/opt/security-reviewer/proxy"]

agents/security-reviewer/proxy/main.go

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"context"
5+
"crypto/subtle"
56
"errors"
67
"fmt"
78
"log"
@@ -10,27 +11,42 @@ import (
1011
"net/http/httputil"
1112
"net/url"
1213
"os"
14+
"os/signal"
1315
"strings"
16+
"syscall"
1417
"time"
1518
)
1619

1720
const (
18-
defaultListenAddr = ":4000"
19-
defaultOpenAIBaseURL = "https://api.openai.com/v1"
21+
// defaultListenAddr is the fallback bind address when none is provided via PROXY_LISTEN_ADDR.
22+
defaultListenAddr = ":4000"
23+
// defaultOpenAIBaseURL is the upstream OpenAI API base path used when none is provided.
24+
defaultOpenAIBaseURL = "https://api.openai.com/v1"
25+
// defaultAnthropicBaseURL is the upstream Anthropic API base path used when none is provided.
2026
defaultAnthropicBaseURL = "https://api.anthropic.com"
21-
openAIInboundPrefix = "/openai/"
22-
anthropicInboundPrefix = "/anthropic/"
23-
healthPath = "/health/liveliness"
24-
headerAuthorization = "Authorization"
25-
headerAnthropicAPIKey = "X-Api-Key"
27+
// openAIInboundPrefix is the path prefix used to route requests to OpenAI.
28+
openAIInboundPrefix = "/openai/"
29+
// anthropicInboundPrefix is the path prefix used to route requests to Anthropic.
30+
anthropicInboundPrefix = "/anthropic/"
31+
// healthPath is the HTTP endpoint used for container health checks.
32+
healthPath = "/health/liveliness"
33+
// headerAuthorization is the inbound HTTP header that carries bearer tokens.
34+
headerAuthorization = "Authorization"
35+
// headerAnthropicAPIKey is the Anthropic-specific header carrying API keys.
36+
headerAnthropicAPIKey = "X-Api-Key"
2637
)
2738

2839
// providerProxy defines how to forward requests to a specific upstream API.
2940
type providerProxy struct {
30-
Prefix string
31-
Target *url.URL
32-
HeaderName string
41+
// Prefix is the inbound path prefix handled by the provider.
42+
Prefix string
43+
// Target is the upstream endpoint used to service requests for the provider.
44+
Target *url.URL
45+
// HeaderName is the outbound header carrying the provider-specific credential.
46+
HeaderName string
47+
// HeaderValue is the credential value set on outbound requests.
3348
HeaderValue string
49+
// DisplayName is the human-readable name of the provider used in logs.
3450
DisplayName string
3551
}
3652

@@ -41,6 +57,9 @@ func main() {
4157
log.Fatalf("proxy configuration error: %v", err)
4258
}
4359

60+
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
61+
defer stop()
62+
4463
mux := http.NewServeMux()
4564
mux.HandleFunc(healthPath, handleHealth)
4665

@@ -63,6 +82,15 @@ func main() {
6382
log.Printf("proxy listening on %s (OpenAI -> %s, Anthropic -> %s)",
6483
cfg.listenAddr, cfg.openAIProxy.Target.String(), cfg.anthropicProxy.Target.String())
6584

85+
go func() {
86+
<-ctx.Done()
87+
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
88+
defer cancel()
89+
if err := server.Shutdown(shutdownCtx); err != nil {
90+
log.Printf("proxy shutdown error: %v", err)
91+
}
92+
}()
93+
6694
if err = server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
6795
log.Fatalf("proxy server error: %v", err)
6896
}
@@ -289,6 +317,8 @@ func firstNonEmpty(values ...string) string {
289317
return ""
290318
}
291319

320+
// validateClientToken ensures inbound requests present the proxy bearer secret using
321+
// a constant-time comparison to avoid leaking timing information.
292322
func validateClientToken(headerValue, expectedToken string) bool {
293323
if expectedToken == "" {
294324
return false
@@ -300,5 +330,6 @@ func validateClientToken(headerValue, expectedToken string) bool {
300330
if !strings.EqualFold(parts[0], "bearer") {
301331
return false
302332
}
303-
return strings.TrimSpace(parts[1]) == expectedToken
333+
provided := strings.TrimSpace(parts[1])
334+
return subtle.ConstantTimeCompare([]byte(provided), []byte(expectedToken)) == 1
304335
}

0 commit comments

Comments
 (0)