Skip to content

Commit

Permalink
internal/appsec: add new AppSec beta functionality and support for co…
Browse files Browse the repository at this point in the history
…ntrib/net/http (#1007)

Beta functionality for AppSec has been added to internal/appsec. It is also integrated into contrib/internal/httputil and can be enabled for all HTTP integrations using this (all do at this point).

The appsec package also has C bindings, which are disabled by default for the beta, but will likely be enabled later on. For this reason, to use AppSec, one must build their program using the "appsec" tag and enable it using DD_APPSEC_ENABLED=true.
  • Loading branch information
Julio-Guerra authored Oct 20, 2021
1 parent 6629934 commit 9046c68
Show file tree
Hide file tree
Showing 45 changed files with 5,850 additions and 52 deletions.
40 changes: 32 additions & 8 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: 2
version: 2.1

plain-go114: &plain-go114
working_directory: /home/circleci/dd-trace-go.v1
Expand All @@ -8,8 +8,13 @@ plain-go114: &plain-go114
GOPATH: "/home/circleci/go"

jobs:
go1.12-build:
go1_12-build:
# Validate that the core builds with go1.12
parameters:
build_tags:
description: "go build tags used to compile"
default: ""
type: string
docker:
- image: circleci/golang:1.12
environment:
Expand All @@ -25,7 +30,7 @@ jobs:
# See https://github.com/DataDog/dd-trace-go/pull/1029
sudo apt update && sudo apt install ca-certificates libgnutls30 -y
go build ./ddtrace/... ./profiler/...
go build -v -tags "<< parameters.build_tags >>" ./ddtrace/... ./profiler/... ./internal/appsec/...
metadata:
<<: *plain-go114
Expand Down Expand Up @@ -83,6 +88,11 @@ jobs:
test-core:
parameters:
build_tags:
description: "go build tags to use to compile the tests"
default: ""
type: string
resource_class: xlarge
environment: # environment variables for the build itself
TEST_RESULTS: /tmp/test-results # path to where test results will be saved
Expand All @@ -98,7 +108,7 @@ jobs:
name: Testing
command: |
PACKAGE_NAMES=$(go list ./... | grep -v /contrib/ | circleci tests split --split-by=timings --timings-type=classname)
gotestsum --junitfile ${TEST_RESULTS}/gotestsum-report.xml -- $PACKAGE_NAMES -v -race -coverprofile=coverage.txt -covermode=atomic
env DD_APPSEC_ENABLED=$(test "<< parameters.build_tags >>" = appsec && echo -n true) gotestsum --junitfile ${TEST_RESULTS}/gotestsum-report.xml -- $PACKAGE_NAMES -v -race -coverprofile=coverage.txt -covermode=atomic -tags "<< parameters.build_tags >>"
- save_cache:
key: go-mod-v4-{{ checksum "go.sum" }}
Expand All @@ -118,6 +128,11 @@ jobs:


test-contrib:
parameters:
build_tags:
description: "go build tags to use to compile the tests"
default: ""
type: string
resource_class: xlarge
environment: # environment variables for the build itself
TEST_RESULTS: /tmp/test-results # path to where test results will be saved
Expand Down Expand Up @@ -241,7 +256,7 @@ jobs:
name: Testing integrations
command: |
PACKAGE_NAMES=$(go list ./contrib/... | grep -v -e grpc.v12 -e google.golang.org/api | circleci tests split --split-by=timings --timings-type=classname)
gotestsum --junitfile ${TEST_RESULTS}/gotestsum-report.xml -- $PACKAGE_NAMES -v -race -coverprofile=coverage.txt -covermode=atomic
env DD_APPSEC_ENABLED=$(test "<< parameters.build_tags >>" = appsec && echo -n true) gotestsum --junitfile ${TEST_RESULTS}/gotestsum-report.xml -- $PACKAGE_NAMES -v -race -coverprofile=coverage.txt -covermode=atomic -tags "<< parameters.build_tags >>"
- save_cache:
key: go-mod-v4-{{ checksum "go.sum" }}
Expand Down Expand Up @@ -288,8 +303,17 @@ workflows:
version: 2
build-and-test:
jobs:
- go1.12-build
- go1_12-build:
matrix:
parameters:
build_tags: [ "", "appsec" ]
- metadata
- lint
- test-core
- test-contrib
- test-core:
matrix:
parameters:
build_tags: [ "", "appsec" ]
- test-contrib:
matrix:
parameters:
build_tags: [ "", "appsec" ]
3 changes: 2 additions & 1 deletion LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Component,Origin,License,Copyright
import,io.opentracing,Apache-2.0,Copyright 2016-2017 The OpenTracing Authors
import,io.opentracing,Apache-2.0,Copyright 2016-2017 The OpenTracing Authors
appsec,https://github.com/DataDog/libddwaf,Apache-2.0 OR BSD-3-Clause,Copyright (c) 2021 Datadog <[email protected]>
19 changes: 15 additions & 4 deletions contrib/internal/httputil/make_responsewriter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions contrib/internal/httputil/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
"gopkg.in/DataDog/dd-trace-go.v1/internal/appsec/dyngo/instrumentation/httpinstr"
)

// TraceConfig defines the configuration for request tracing.
Expand Down Expand Up @@ -53,8 +54,7 @@ func TraceAndServe(h http.Handler, cfg *TraceConfig) {
defer span.Finish(cfg.FinishOpts...)

cfg.ResponseWriter = wrapResponseWriter(cfg.ResponseWriter, span)

h.ServeHTTP(cfg.ResponseWriter, cfg.Request.WithContext(ctx))
httpinstr.WrapHandler(h, span).ServeHTTP(cfg.ResponseWriter, cfg.Request.WithContext(ctx))
}

// responseWriter is a small wrapper around an http response writer that will
Expand All @@ -69,8 +69,13 @@ func newResponseWriter(w http.ResponseWriter, span ddtrace.Span) *responseWriter
return &responseWriter{w, span, 0}
}

// Status returns the status code that was monitored.
func (w *responseWriter) Status() int {
return w.status
}

// Write writes the data to the connection as part of an HTTP reply.
// We explicitely call WriteHeader with the 200 status code
// We explicitly call WriteHeader with the 200 status code
// in order to get it reported into the span.
func (w *responseWriter) Write(b []byte) (int, error) {
if w.status == 0 {
Expand Down
66 changes: 35 additions & 31 deletions contrib/internal/httputil/trace_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions ddtrace/tracer/log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ func TestStartupLog(t *testing.T) {
}

func TestLogSamplingRules(t *testing.T) {
// Disable AppSec to avoid their logs
if old := os.Getenv("DD_APPSEC_ENABLED"); old != "" {
os.Unsetenv("DD_APPSEC_ENABLED")
defer os.Setenv("DD_APPSEC_ENABLED", old)
}
assert := assert.New(t)
tp := new(testLogger)
os.Setenv("DD_TRACE_SAMPLING_RULES", `[{"service": "some.service", "sample_rate": 0.234}, {"service": "other.service"}, {"service": "last.service", "sample_rate": 0.56}, {"odd": "pairs"}, {"sample_rate": 9.10}]`)
Expand Down
10 changes: 9 additions & 1 deletion ddtrace/tracer/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ func (c *config) HasFeature(f string) bool {
return ok
}

// client returns the HTTP client to use.
func (c *config) client() *http.Client {
if c.httpClient == nil {
return defaultClient
}
return c.httpClient
}

// StartOption represents a function that can be provided as a parameter to Start.
type StartOption func(*config)

Expand Down Expand Up @@ -215,7 +223,7 @@ func newConfig(opts ...StartOption) *config {
}
}
if c.transport == nil {
c.transport = newHTTPTransport(c.agentAddr, c.httpClient)
c.transport = newHTTPTransport(c.agentAddr, c.client())
}
if c.propagator == nil {
c.propagator = NewPropagator(nil)
Expand Down
10 changes: 10 additions & 0 deletions ddtrace/tracer/option_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package tracer

import (
"math"
"net/http"
"os"
"path/filepath"
"testing"
Expand Down Expand Up @@ -38,6 +39,15 @@ func TestTracerOptionsDefaults(t *testing.T) {
assert.Equal("localhost:8126", c.agentAddr)
assert.Equal("localhost:8125", c.dogstatsdAddr)
assert.Nil(nil, c.httpClient)
assert.Equal(defaultClient, c.client())
})

t.Run("http-client", func(t *testing.T) {
c := newConfig()
assert.Equal(t, defaultClient, c.client())
client := &http.Client{}
WithHTTPClient(client)(c)
assert.Equal(t, client, c.client())
})

t.Run("analytics", func(t *testing.T) {
Expand Down
Loading

0 comments on commit 9046c68

Please sign in to comment.