From b64559076d841cc5ed5d7ad7f44dc8a56c7d089a Mon Sep 17 00:00:00 2001 From: Aleksander Sekowski Date: Mon, 17 Aug 2026 20:52:38 -0700 Subject: [PATCH 1/2] Fix onboarding so documented make targets actually build A fresh clone could not follow the README: make deps/generate/docker-build/health-check did not exist, make bindings looked for a repo-root openrtb.proto, rust/cargo.toml was not a Cargo.toml, and Docker HEALTHCHECK called a flag the binary did not implement. Closes #17. --- .dockerignore | 12 +++ Dockerfile | 4 +- Makefile | 160 +++++++++++++++++++++++++------- README.md | 45 ++++----- cmd/agent/main.go | 14 +++ docker-compose.yml | 6 +- docs/00-EXAMPLE.md | 13 ++- internal/health/health.go | 24 +++++ internal/health/health_test.go | 63 +++++++++++++ rust/{cargo.toml => Cargo.toml} | 0 rust/Dockerfile | 2 +- scripts/generate.sh | 5 +- 12 files changed, 281 insertions(+), 67 deletions(-) create mode 100644 .dockerignore create mode 100644 internal/health/health_test.go rename rust/{cargo.toml => Cargo.toml} (100%) diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..331604e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +# Local build artifacts. Without this, `docker build` sends rust/target +# and ./artf-agent (hundreds of MB) as context. +artf-agent +artf-agent.exe +rust/target +coverage.out +coverage.html +.git +.DS_Store +*.log +tmp/ +temp/ diff --git a/Dockerfile b/Dockerfile index d73ff07..10a63ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -84,9 +84,9 @@ USER nobody # Expose ports (gRPC: 50051, Web/MCP: 8081, Health: 8080) EXPOSE 50051 8081 8080 -# Health check +# Health check uses the same binary (the image has no curl/wget). HEALTHCHECK --interval=5s --timeout=3s --start-period=5s --retries=3 \ - CMD ["/artf-agent", "-health-check"] || exit 1 + CMD ["/artf-agent", "-health-check"] # Set entrypoint ENTRYPOINT ["/artf-agent"] diff --git a/Makefile b/Makefile index 5f032ff..ee92842 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,85 @@ -# Agentic RTB Framework Makefile - -BINARY=artf-agent -LANGUAGES=go # cpp go csharp objc python ruby js - -# Go build and run targets -.PHONY: build run-all run-grpc run-mcp run-web test +# Agentic Real Time Framework +# +# You do not need protoc to build the reference implementations. +# Generated Go lives in pkg/pb/. The Rust service compiles protos in build.rs. +# `make bindings` / `make generate` regenerate Go from proto/ and are optional. + +BINARY ?= artf-agent +IMAGE ?= artf-agent +RUST_DIR := rust +RUST_BINARY := $(RUST_DIR)/target/release/agentic-rtb-framework-service +PROTO_DIR := proto +OPENRTB_PROTO := $(PROTO_DIR)/com/iabtechlab/openrtb/v2/openrtb.proto +ARTF_PROTO := $(PROTO_DIR)/agenticrtbframework.proto +GRPC_ADDR ?= localhost:50051 +HEALTH_URL ?= http://localhost:8080 +SAMPLE_SERVICE := com.iabtechlab.bidstream.mutation.services.v1.RTBExtensionPoint/GetMutations + +.DEFAULT_GOAL := build + +.PHONY: help deps fetch-openrtb generate bindings build run run-dev run-all \ + run-grpc run-mcp run-web test test-coverage lint clean \ + build-rust run-rust build-all \ + docker-build docker-run docker-run-all docker-compose-up docker-compose-down \ + health-check grpc-test sample-banner sample-video sample-bidshade \ + check docs watch + +help: + @echo "Correct way of building ARTF (issue #17):" + @echo " make deps # go mod download" + @echo " make build # Go agent -> ./$(BINARY)" + @echo " make build-rust # Rust reference service" + @echo " make test # go test ./..." + @echo " make docker-build # container image $(IMAGE)" + @echo "" + @echo "Protobuf Go is checked in under pkg/pb/. Regeneration is optional:" + @echo " make generate # confirm vendored proto + pkg/pb/" + @echo " make bindings # same; proto lives under $(PROTO_DIR)/, not repo root" + @echo "" + @echo "Run (requires a built binary):" + @echo " make run-all # gRPC + MCP + web + health" + @echo " make health-check # curl $(HEALTH_URL)/health/{live,ready}" + @echo " make grpc-test # grpcurl sample against $(GRPC_ADDR)" + +# --- Go --- + +deps: + go mod download + +# Proto is vendored. This target exists because scripts/generate.sh tells +# people to run it; it is a no-op when the file is already present. +fetch-openrtb: + @test -f "$(OPENRTB_PROTO)" || { \ + echo "OpenRTB proto not found at $(OPENRTB_PROTO)"; \ + echo "Expected vendored file proto/com/iabtechlab/openrtb/v2/openrtb.proto"; \ + exit 1; \ + } + @echo "OpenRTB proto vendored at $(OPENRTB_PROTO)" + +generate: fetch-openrtb + @test -f pkg/pb/artf/agenticrtbframework.pb.go + @echo "Protobuf Go is checked in under pkg/pb/. Skipping regeneration (not required to build)." + @echo "To regenerate from proto/: ./scripts/generate.sh" + +# Historical target. It used to invoke protoc on a repo-root openrtb.proto that +# does not exist. Point at the vendored tree; do not require a regen to build. +bindings: fetch-openrtb + @test -f "$(OPENRTB_PROTO)" + @test -f "$(ARTF_PROTO)" + @echo "Vendored proto sources:" + @echo " $(OPENRTB_PROTO)" + @echo " $(ARTF_PROTO)" + @echo "Checked-in Go bindings: pkg/pb/" + @echo "There is no openrtb.proto at the repo root. Regeneration: ./scripts/generate.sh" build: go build -o $(BINARY) ./cmd/agent +run: run-all + +run-dev: build + ./$(BINARY) --enable-grpc --enable-mcp --enable-web + run-all: build ./$(BINARY) --enable-grpc --enable-mcp --enable-web @@ -24,40 +95,65 @@ run-web: build test: go test ./... -# Rust build and run targets -RUST_BINARY=rust/target/release/agentic-rtb-framework-service +test-coverage: + go test ./... -coverprofile=coverage.out + go tool cover -func=coverage.out -.PHONY: build-rust run-rust build-all +lint: + go vet ./... + +clean: + rm -f $(BINARY) coverage.out coverage.html + rm -rf $(RUST_DIR)/target + +# --- Rust --- build-rust: - cd rust && cargo build --release + cd $(RUST_DIR) && cargo build --release run-rust: build-rust ARTF_GRPC_SERVER_PORT=50053 ARTF_HTTP_SERVER_PORT=8082 $(RUST_BINARY) build-all: build build-rust -# Protobuf targets +# --- Docker --- -bindings: - for x in ${LANGUAGES}; do \ - protoc --proto_path=. \ - --$${x}_out=. \ - --experimental_editions \ - openrtb.proto agenticrtbframework.proto; \ - protoc --proto_path=. \ - --$${x}_out=. \ - --$${x}-grpc_out=require_unimplemented_servers=false:. \ - agenticrtbframeworkservices.proto; \ - done +docker-build: + docker build -t $(IMAGE) . -check: - prototool lint +docker-run: docker-run-all -clean: - for x in ${LANGUAGES}; do \ - rm -fr $${x}/*; \ - done +docker-run-all: docker-build + docker run --rm -p 50051:50051 -p 8081:8081 -p 8080:8080 $(IMAGE) + +docker-compose-up: + docker compose up --build -d + +docker-compose-down: + docker compose down + +# --- Live checks (server must already be running) --- + +health-check: + curl -fsS $(HEALTH_URL)/health/live + @echo + curl -fsS $(HEALTH_URL)/health/ready + @echo + +grpc-test: sample-banner + +sample-banner: + grpcurl -plaintext -d @ $(GRPC_ADDR) $(SAMPLE_SERVICE) < samples/banner-basic.json + +sample-video: + grpcurl -plaintext -d @ $(GRPC_ADDR) $(SAMPLE_SERVICE) < samples/video-deals.json + +sample-bidshade: + grpcurl -plaintext -d @ $(GRPC_ADDR) $(SAMPLE_SERVICE) < samples/bid-shading.json + +# Spec leftovers. prototool is not required to build. +check: + @echo "prototool is not part of the reference build. Use: make test" docs: podman run --rm \ @@ -65,8 +161,8 @@ docs: -w ${PWD} \ pseudomuto/protoc-gen-doc \ --doc_opt=html,doc.html \ - --proto_path=${PWD} \ - openrtb.proto agenticrtbframework.proto agenticrtbframeworkservices.proto + --proto_path=${PWD}/$(PROTO_DIR) \ + com/iabtechlab/openrtb/v2/openrtb.proto agenticrtbframework.proto watch: - fswatch -r ./ | xargs -n1 make docs + fswatch -r ./ | xargs -n1 make docs diff --git a/README.md b/README.md index 0bfcc9a..fdcc49a 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,16 @@ https://iabtechlab.com/standards/artf/ #### How to get started -Download the openRTB official 2.6 Protocol Buffers specification from https://github.com/InteractiveAdvertisingBureau/openrtb2.x/blob/main/proto/src/main/com/iabtechlab/openrtb/v2/openrtb.proto to this directory. +OpenRTB 2.6 protobufs are vendored at `proto/com/iabtechlab/openrtb/v2/openrtb.proto`. Generated Go is checked in under `pkg/pb/`. You do not need to download protos or run `protoc` to build. -From the command line: +```bash +make deps +make build # Go agent -> ./artf-agent +make build-rust # Rust reference service (optional) +make test +``` -1. Install `make` and the latest version of `protoc`. -2. Open the `Makefile` and choose the language(s) for which the Protocol Buffers - object code should be generated. -3. Run `make`. +`make generate` / `make bindings` are optional. They confirm the vendored proto paths; they do not look for a repo-root `openrtb.proto`. #### Contact For more information, or to get involved, please email support@iabtechlab.com. @@ -49,13 +51,14 @@ This project implements a multi-protocol server that conforms to the ARTF specif #### Prerequisites -- Go 1.23+ -- Protocol Buffers compiler (`protoc`) v3.21+ +- Go 1.23+ (required to build the Go agent) +- Rust toolchain (optional, for `make build-rust`) - Docker (optional, for containerized deployment) +- `protoc` v3.21+ and the Go plugins (optional, only if regenerating `pkg/pb/`) -#### Critical Dependencies +#### Optional: regenerating protobuf code -The following tools must be installed to generate protobuf code: +Checked-in generated Go in `pkg/pb/` is enough to build. The tools below are only needed for `./scripts/generate.sh`: | Tool | Version | Installation | |------|---------|--------------| @@ -79,19 +82,19 @@ Go module dependencies (managed via `go.mod`): #### Build and Run ```bash -# Install dependencies +# Install Go module dependencies make deps -# Generate protobuf code -make generate - -# Build the server +# Build the Go server (uses checked-in pkg/pb/; protoc not required) make build +# Optional: build the Rust reference service +make build-rust + # Run with all services enabled make run-all -# Run in development mode (verbose) +# Run in development mode (same flags, after a local build) make run-dev ``` @@ -169,6 +172,7 @@ The MCP server exposes an `extend_rtb` tool that accepts OpenRTB bid requests an | `--mcp-port` | 50052 | MCP server port (ignored when both Web and MCP enabled) | | `--web-port` | 8081 | Web interface port | | `--health-port` | 8080 | Health check HTTP port | +| `--health-check` | false | Probe `http://127.0.0.1:/health/ready` and exit (Docker HEALTHCHECK) | #### Load Balancer Configuration @@ -193,16 +197,13 @@ make test # Run with coverage make test-coverage -# Test gRPC endpoint (requires grpcurl) +# Test gRPC endpoint (requires a running agent and grpcurl) make grpc-test -# Test MCP endpoint -make mcp-test - -# Check health endpoints +# Check health endpoints (requires a running agent) make health-check -# Send sample requests via MCP +# Send bundled samples over gRPC (requires a running agent and grpcurl) make sample-banner make sample-video make sample-bidshade diff --git a/cmd/agent/main.go b/cmd/agent/main.go index 867a691..a0b987b 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -72,6 +72,9 @@ var ( // Version flag showVersion = flag.Bool("version", false, "Show version information") + + // One-shot probe for Docker HEALTHCHECK / compose. Does not start the server. + healthCheck = flag.Bool("health-check", false, "Probe local /health/ready and exit 0/1") ) func main() { @@ -83,6 +86,17 @@ func main() { os.Exit(0) } + if *healthCheck { + origin := fmt.Sprintf("http://127.0.0.1:%d", *healthPort) + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + if err := health.Probe(ctx, origin); err != nil { + log.Printf("health-check: %v", err) + os.Exit(1) + } + os.Exit(0) + } + log.Printf("Starting ARTF Agent v%s", Version) log.Printf("Features: gRPC=%v, MCP=%v, Web=%v", *enableGRPC, *enableMCP, *enableWeb) diff --git a/docker-compose.yml b/docker-compose.yml index 8438cee..8aa0ee1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,7 +24,7 @@ services: - "--web-port=8081" - "--health-port=8080" healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health/ready"] + test: ["CMD", "/artf-agent", "-health-check"] interval: 10s timeout: 5s retries: 3 @@ -61,7 +61,7 @@ services: - "--enable-mcp=false" - "--enable-web=false" healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health/ready"] + test: ["CMD", "/artf-agent", "-health-check"] interval: 10s timeout: 5s retries: 3 @@ -87,7 +87,7 @@ services: - "--enable-mcp" - "--enable-web=false" healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health/ready"] + test: ["CMD", "/artf-agent", "-health-check"] interval: 10s timeout: 5s retries: 3 diff --git a/docs/00-EXAMPLE.md b/docs/00-EXAMPLE.md index ac8a9d8..ae42a02 100644 --- a/docs/00-EXAMPLE.md +++ b/docs/00-EXAMPLE.md @@ -325,18 +325,20 @@ readinessProbe: | Command | Description | |---------|-------------| | `make deps` | Download Go dependencies | -| `make generate` | Generate protobuf Go code | -| `make build` | Build server binary | +| `make generate` | Confirm vendored protos / checked-in `pkg/pb/` (does not require protoc) | +| `make build` | Build the Go agent binary | +| `make build-rust` | Build the Rust reference service (`rust/Cargo.toml`) | | `make test` | Run unit tests | | `make test-coverage` | Run tests with coverage report | -| `make lint` | Run linter | -| `make clean` | Remove build artifacts | +| `make lint` | `go vet ./...` | +| `make clean` | Remove build artifacts (`artf-agent`, `rust/target`, coverage files) | ### Run Commands | Command | Description | |---------|-------------| -| `make run` | Run server locally | +| `make run` | Run server locally (gRPC + MCP + web) | +| `make run-all` | Same as `make run` | | `make docker-build` | Build Docker image | | `make docker-run` | Run Docker container | | `make docker-compose-up` | Start with docker-compose | @@ -359,6 +361,7 @@ readinessProbe: |------|---------|-------------| | `-grpc-port` | 50051 | gRPC server listening port | | `-health-port` | 8080 | Health check HTTP server port | +| `-health-check` | false | Probe local `/health/ready` and exit 0/1 (container HEALTHCHECK) | ### Environment Variables diff --git a/internal/health/health.go b/internal/health/health.go index d810649..da4d8d7 100644 --- a/internal/health/health.go +++ b/internal/health/health.go @@ -19,9 +19,13 @@ package health import ( + "context" "encoding/json" + "fmt" "net/http" + "strings" "sync" + "time" ) // Checker implements liveness and readiness probes @@ -93,3 +97,23 @@ func (c *Checker) ReadinessHandler(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(response) } + +// Probe GETs origin/health/ready. Used by the process-local -health-check flag +// so Docker HEALTHCHECK does not need curl or wget in the image. +func Probe(ctx context.Context, origin string) error { + u := strings.TrimRight(origin, "/") + "/health/ready" + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) + if err != nil { + return err + } + client := &http.Client{Timeout: 2 * time.Second} + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("%s returned %s", u, resp.Status) + } + return nil +} diff --git a/internal/health/health_test.go b/internal/health/health_test.go new file mode 100644 index 0000000..e7d6e13 --- /dev/null +++ b/internal/health/health_test.go @@ -0,0 +1,63 @@ +// Copyright (c) 2025 Index Exchange Inc. +// +// This file is part of the Agentic RTB Framework reference implementation. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package health + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + "time" +) + +func TestProbeReady(t *testing.T) { + checker := NewChecker() + checker.SetReady(true) + mux := http.NewServeMux() + mux.HandleFunc("/health/ready", checker.ReadinessHandler) + srv := httptest.NewServer(mux) + defer srv.Close() + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + if err := Probe(ctx, srv.URL); err != nil { + t.Fatalf("Probe ready: %v", err) + } +} + +func TestProbeNotReady(t *testing.T) { + checker := NewChecker() + mux := http.NewServeMux() + mux.HandleFunc("/health/ready", checker.ReadinessHandler) + srv := httptest.NewServer(mux) + defer srv.Close() + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + if err := Probe(ctx, srv.URL); err == nil { + t.Fatal("Probe expected error when not ready") + } +} + +func TestProbeUnreachable(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + if err := Probe(ctx, "http://127.0.0.1:1"); err == nil { + t.Fatal("Probe expected error for unreachable origin") + } +} \ No newline at end of file diff --git a/rust/cargo.toml b/rust/Cargo.toml similarity index 100% rename from rust/cargo.toml rename to rust/Cargo.toml diff --git a/rust/Dockerfile b/rust/Dockerfile index 379d8da..a5077be 100644 --- a/rust/Dockerfile +++ b/rust/Dockerfile @@ -33,7 +33,7 @@ RUN mkdir -p ${BASE_DIR}/proto COPY proto/*.proto ${BASE_DIR}/proto/ COPY src/*.rs ./src/ -COPY cargo.toml ./Cargo.toml +COPY Cargo.toml Cargo.lock ./ RUN cargo install --path . RUN apt-get update && apt-get install -y protobuf-compiler diff --git a/scripts/generate.sh b/scripts/generate.sh index 2570cbf..3f95321 100755 --- a/scripts/generate.sh +++ b/scripts/generate.sh @@ -12,13 +12,14 @@ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" PROTO_DIR="$PROJECT_ROOT/proto" OUT_DIR="$PROJECT_ROOT/pkg/pb" -# OpenRTB proto location (downloaded by make fetch-openrtb) +# Vendored OpenRTB 2.6 proto. The source import path says v2.6/; the file +# lives under v2/. See issue #11. make fetch-openrtb verifies this path. OPENRTB_PROTO="$PROTO_DIR/com/iabtechlab/openrtb/v2/openrtb.proto" # Check if OpenRTB proto exists if [ ! -f "$OPENRTB_PROTO" ]; then echo "Error: OpenRTB proto not found at $OPENRTB_PROTO" - echo "Run 'make fetch-openrtb' to download it from IAB Tech Lab repository" + echo "It is vendored in this repository. Run 'make fetch-openrtb' to confirm." exit 1 fi From 27a2298d01b1ae6a0b513180fecdf781182fc76f Mon Sep 17 00:00:00 2001 From: Aleksander Sekowski Date: Mon, 17 Aug 2026 21:45:42 -0700 Subject: [PATCH 2/2] Keep spec protobuf targets; wire generate to generate.sh Do not no-op bindings/check/docs or rewrite the spec getting-started block. The Go agent still builds from checked-in pkg/pb/ without protoc. --- Makefile | 103 ++++++++++++++------------------- README.md | 21 ++++--- docs/00-EXAMPLE.md | 13 ++--- internal/health/health_test.go | 2 +- scripts/generate.sh | 8 +-- 5 files changed, 64 insertions(+), 83 deletions(-) diff --git a/Makefile b/Makefile index ee92842..d3274d1 100644 --- a/Makefile +++ b/Makefile @@ -1,84 +1,54 @@ -# Agentic Real Time Framework -# -# You do not need protoc to build the reference implementations. -# Generated Go lives in pkg/pb/. The Rust service compiles protos in build.rs. -# `make bindings` / `make generate` regenerate Go from proto/ and are optional. +# Agentic RTB Framework Makefile -BINARY ?= artf-agent +BINARY=artf-agent IMAGE ?= artf-agent -RUST_DIR := rust -RUST_BINARY := $(RUST_DIR)/target/release/agentic-rtb-framework-service -PROTO_DIR := proto -OPENRTB_PROTO := $(PROTO_DIR)/com/iabtechlab/openrtb/v2/openrtb.proto -ARTF_PROTO := $(PROTO_DIR)/agenticrtbframework.proto +LANGUAGES=go # cpp go csharp objc python ruby js +RUST_BINARY=rust/target/release/agentic-rtb-framework-service GRPC_ADDR ?= localhost:50051 HEALTH_URL ?= http://localhost:8080 SAMPLE_SERVICE := com.iabtechlab.bidstream.mutation.services.v1.RTBExtensionPoint/GetMutations .DEFAULT_GOAL := build -.PHONY: help deps fetch-openrtb generate bindings build run run-dev run-all \ - run-grpc run-mcp run-web test test-coverage lint clean \ +.PHONY: help deps generate build run run-dev run-all run-grpc run-mcp run-web \ + test test-coverage lint \ build-rust run-rust build-all \ docker-build docker-run docker-run-all docker-compose-up docker-compose-down \ health-check grpc-test sample-banner sample-video sample-bidshade \ - check docs watch + bindings check clean docs watch help: - @echo "Correct way of building ARTF (issue #17):" + @echo "Reference agents (checked-in pkg/pb/; protoc not required):" @echo " make deps # go mod download" @echo " make build # Go agent -> ./$(BINARY)" @echo " make build-rust # Rust reference service" @echo " make test # go test ./..." @echo " make docker-build # container image $(IMAGE)" @echo "" - @echo "Protobuf Go is checked in under pkg/pb/. Regeneration is optional:" - @echo " make generate # confirm vendored proto + pkg/pb/" - @echo " make bindings # same; proto lives under $(PROTO_DIR)/, not repo root" + @echo "Regenerate protobufs (requires protoc; not needed to build the agents):" + @echo " make generate # Go: scripts/generate.sh" + @echo " make bindings # spec language bindings (repo-root protos)" @echo "" @echo "Run (requires a built binary):" @echo " make run-all # gRPC + MCP + web + health" @echo " make health-check # curl $(HEALTH_URL)/health/{live,ready}" @echo " make grpc-test # grpcurl sample against $(GRPC_ADDR)" -# --- Go --- +# Go build and run targets deps: go mod download -# Proto is vendored. This target exists because scripts/generate.sh tells -# people to run it; it is a no-op when the file is already present. -fetch-openrtb: - @test -f "$(OPENRTB_PROTO)" || { \ - echo "OpenRTB proto not found at $(OPENRTB_PROTO)"; \ - echo "Expected vendored file proto/com/iabtechlab/openrtb/v2/openrtb.proto"; \ - exit 1; \ - } - @echo "OpenRTB proto vendored at $(OPENRTB_PROTO)" - -generate: fetch-openrtb - @test -f pkg/pb/artf/agenticrtbframework.pb.go - @echo "Protobuf Go is checked in under pkg/pb/. Skipping regeneration (not required to build)." - @echo "To regenerate from proto/: ./scripts/generate.sh" - -# Historical target. It used to invoke protoc on a repo-root openrtb.proto that -# does not exist. Point at the vendored tree; do not require a regen to build. -bindings: fetch-openrtb - @test -f "$(OPENRTB_PROTO)" - @test -f "$(ARTF_PROTO)" - @echo "Vendored proto sources:" - @echo " $(OPENRTB_PROTO)" - @echo " $(ARTF_PROTO)" - @echo "Checked-in Go bindings: pkg/pb/" - @echo "There is no openrtb.proto at the repo root. Regeneration: ./scripts/generate.sh" +# Go protobuf regen. Not required to build; pkg/pb/ is checked in. +generate: + scripts/generate.sh build: go build -o $(BINARY) ./cmd/agent run: run-all -run-dev: build - ./$(BINARY) --enable-grpc --enable-mcp --enable-web +run-dev: run-all run-all: build ./$(BINARY) --enable-grpc --enable-mcp --enable-web @@ -102,21 +72,17 @@ test-coverage: lint: go vet ./... -clean: - rm -f $(BINARY) coverage.out coverage.html - rm -rf $(RUST_DIR)/target - -# --- Rust --- +# Rust build and run targets build-rust: - cd $(RUST_DIR) && cargo build --release + cd rust && cargo build --release run-rust: build-rust ARTF_GRPC_SERVER_PORT=50053 ARTF_HTTP_SERVER_PORT=8082 $(RUST_BINARY) build-all: build build-rust -# --- Docker --- +# Docker docker-build: docker build -t $(IMAGE) . @@ -132,7 +98,7 @@ docker-compose-up: docker-compose-down: docker compose down -# --- Live checks (server must already be running) --- +# Live checks (server must already be running) health-check: curl -fsS $(HEALTH_URL)/health/live @@ -151,9 +117,28 @@ sample-video: sample-bidshade: grpcurl -plaintext -d @ $(GRPC_ADDR) $(SAMPLE_SERVICE) < samples/bid-shading.json -# Spec leftovers. prototool is not required to build. +# Protobuf targets + +bindings: + for x in ${LANGUAGES}; do \ + protoc --proto_path=. \ + --$${x}_out=. \ + --experimental_editions \ + openrtb.proto agenticrtbframework.proto; \ + protoc --proto_path=. \ + --$${x}_out=. \ + --$${x}-grpc_out=require_unimplemented_servers=false:. \ + agenticrtbframeworkservices.proto; \ + done + check: - @echo "prototool is not part of the reference build. Use: make test" + prototool lint + +clean: + for x in ${LANGUAGES}; do \ + rm -fr $${x}/*; \ + done + rm -f $(BINARY) coverage.out coverage.html docs: podman run --rm \ @@ -161,8 +146,8 @@ docs: -w ${PWD} \ pseudomuto/protoc-gen-doc \ --doc_opt=html,doc.html \ - --proto_path=${PWD}/$(PROTO_DIR) \ - com/iabtechlab/openrtb/v2/openrtb.proto agenticrtbframework.proto + --proto_path=${PWD} \ + openrtb.proto agenticrtbframework.proto agenticrtbframeworkservices.proto watch: - fswatch -r ./ | xargs -n1 make docs + fswatch -r ./ | xargs -n1 make docs diff --git a/README.md b/README.md index fdcc49a..7d8d56c 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,14 @@ https://iabtechlab.com/standards/artf/ #### How to get started -OpenRTB 2.6 protobufs are vendored at `proto/com/iabtechlab/openrtb/v2/openrtb.proto`. Generated Go is checked in under `pkg/pb/`. You do not need to download protos or run `protoc` to build. +Download the openRTB official 2.6 Protocol Buffers specification from https://github.com/InteractiveAdvertisingBureau/openrtb2.x/blob/main/proto/src/main/com/iabtechlab/openrtb/v2/openrtb.proto to this directory. -```bash -make deps -make build # Go agent -> ./artf-agent -make build-rust # Rust reference service (optional) -make test -``` +From the command line: -`make generate` / `make bindings` are optional. They confirm the vendored proto paths; they do not look for a repo-root `openrtb.proto`. +1. Install `make` and the latest version of `protoc`. +2. Open the `Makefile` and choose the language(s) for which the Protocol Buffers + object code should be generated. +3. Run `make`. #### Contact For more information, or to get involved, please email support@iabtechlab.com. @@ -54,11 +52,12 @@ This project implements a multi-protocol server that conforms to the ARTF specif - Go 1.23+ (required to build the Go agent) - Rust toolchain (optional, for `make build-rust`) - Docker (optional, for containerized deployment) -- `protoc` v3.21+ and the Go plugins (optional, only if regenerating `pkg/pb/`) + +Checked-in generated Go in `pkg/pb/` is enough to `make build`. You do not need to download OpenRTB or run `protoc` to build the agent. #### Optional: regenerating protobuf code -Checked-in generated Go in `pkg/pb/` is enough to build. The tools below are only needed for `./scripts/generate.sh`: +`make generate` runs `scripts/generate.sh`. It is not required to build. The tools below are only needed for that regen: | Tool | Version | Installation | |------|---------|--------------| @@ -94,7 +93,7 @@ make build-rust # Run with all services enabled make run-all -# Run in development mode (same flags, after a local build) +# Same as make run-all make run-dev ``` diff --git a/docs/00-EXAMPLE.md b/docs/00-EXAMPLE.md index ae42a02..76e416d 100644 --- a/docs/00-EXAMPLE.md +++ b/docs/00-EXAMPLE.md @@ -315,23 +315,22 @@ readinessProbe: ### Prerequisites -- Go 1.22+ -- Protocol Buffers compiler (`protoc`) -- protoc-gen-go and protoc-gen-go-grpc plugins -- Docker (for containerized deployment) +- Go 1.23+ (required to `make build`) +- Protocol Buffers compiler (`protoc`) and Go plugins (optional: `make generate`) +- Docker (optional, for containerized deployment) ### Build Commands | Command | Description | |---------|-------------| | `make deps` | Download Go dependencies | -| `make generate` | Confirm vendored protos / checked-in `pkg/pb/` (does not require protoc) | -| `make build` | Build the Go agent binary | +| `make generate` | Regenerate protobuf Go via `scripts/generate.sh` (requires protoc; not required to `make build`) | +| `make build` | Build the Go agent binary from checked-in `pkg/pb/` | | `make build-rust` | Build the Rust reference service (`rust/Cargo.toml`) | | `make test` | Run unit tests | | `make test-coverage` | Run tests with coverage report | | `make lint` | `go vet ./...` | -| `make clean` | Remove build artifacts (`artf-agent`, `rust/target`, coverage files) | +| `make clean` | Remove spec language output dirs, `artf-agent`, and coverage files | ### Run Commands diff --git a/internal/health/health_test.go b/internal/health/health_test.go index e7d6e13..49d6d02 100644 --- a/internal/health/health_test.go +++ b/internal/health/health_test.go @@ -60,4 +60,4 @@ func TestProbeUnreachable(t *testing.T) { if err := Probe(ctx, "http://127.0.0.1:1"); err == nil { t.Fatal("Probe expected error for unreachable origin") } -} \ No newline at end of file +} diff --git a/scripts/generate.sh b/scripts/generate.sh index 3f95321..2fe2d69 100755 --- a/scripts/generate.sh +++ b/scripts/generate.sh @@ -2,8 +2,8 @@ # Generate Go code from protobuf definitions # Requires: protoc, protoc-gen-go, protoc-gen-go-grpc # -# OpenRTB 2.6 proto is fetched from IAB Tech Lab repository: -# https://github.com/IABTechLab/openrtb-proto-v2 +# OpenRTB 2.6 proto is vendored at proto/com/iabtechlab/openrtb/v2/openrtb.proto +# (the source import path says v2.6/; the file lives under v2/). set -e @@ -12,14 +12,12 @@ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" PROTO_DIR="$PROJECT_ROOT/proto" OUT_DIR="$PROJECT_ROOT/pkg/pb" -# Vendored OpenRTB 2.6 proto. The source import path says v2.6/; the file -# lives under v2/. See issue #11. make fetch-openrtb verifies this path. OPENRTB_PROTO="$PROTO_DIR/com/iabtechlab/openrtb/v2/openrtb.proto" # Check if OpenRTB proto exists if [ ! -f "$OPENRTB_PROTO" ]; then echo "Error: OpenRTB proto not found at $OPENRTB_PROTO" - echo "It is vendored in this repository. Run 'make fetch-openrtb' to confirm." + echo "It is vendored at proto/com/iabtechlab/openrtb/v2/openrtb.proto" exit 1 fi