Skip to content

Commit 426f359

Browse files
authored
Merge pull request #1 from cruxstack/dev
feat: implement initial version of service
2 parents 63f883f + 8d2b6c7 commit 426f359

35 files changed

Lines changed: 2040 additions & 0 deletions

.dockerignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.git
2+
.gitignore
3+
bin
4+
tmp
5+
.DS_Store

.editorconfig

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[*]
2+
indent_style = space
3+
indent_size = 2
4+
end_of_line = lf
5+
insert_final_newline = true
6+
trim_trailing_whitespace = true
7+
charset = utf-8
8+
9+
[{Dockerfile,Dockerfile.*}]
10+
indent_size = 4
11+
tab_width = 4
12+
13+
[{Makefile,makefile,GNUmakefile}]
14+
indent_style = tab
15+
indent_size = 4
16+
17+
[Makefile.*]
18+
indent_style = tab
19+
indent_size = 4
20+
21+
[**/*.{go,mod,sum}]
22+
indent_style = tab
23+
indent_size = unset
24+
25+
[**/*.py]
26+
indent_size = 4

.github/dependabot.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "github-actions"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
8+
- package-ecosystem: "gomod"
9+
directory: "/"
10+
schedule:
11+
interval: "weekly"

.github/workflows/ci.yaml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
name: ci
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
lint:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout Code
19+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
20+
21+
- name: Setup Go
22+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
23+
with:
24+
go-version: '1.26.2'
25+
26+
- name: Run go vet
27+
run: go vet ./...
28+
29+
- name: Check formatting
30+
run: |
31+
unformatted=$(gofmt -l .)
32+
if [ -n "$unformatted" ]; then
33+
echo "The following files are not formatted:"
34+
echo "$unformatted"
35+
exit 1
36+
fi
37+
38+
test-unit:
39+
runs-on: ubuntu-latest
40+
steps:
41+
- name: Checkout Code
42+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
43+
44+
- name: Setup Go
45+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
46+
with:
47+
go-version: '1.26.2'
48+
49+
- name: Run unit tests
50+
run: make test-unit
51+
52+
test-integration:
53+
runs-on: ubuntu-latest
54+
steps:
55+
- name: Checkout Code
56+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
57+
58+
- name: Setup Go
59+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
60+
with:
61+
go-version: '1.26.2'
62+
63+
- name: Run integration tests
64+
run: make test-integration
65+
66+
build:
67+
runs-on: ubuntu-latest
68+
steps:
69+
- name: Checkout Code
70+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
71+
72+
- name: Setup Go
73+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
74+
with:
75+
go-version: '1.26.2'
76+
77+
- name: Build
78+
run: make build

.github/workflows/release.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: release
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout Code
16+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
17+
- name: Bump Version
18+
id: tag_version
19+
uses: mathieudutour/github-tag-action@a22cf08638b34d5badda920f9daf6e72c477b07b # v6.2.0
20+
with:
21+
github_token: ${{ secrets.GITHUB_TOKEN }}
22+
default_bump: minor
23+
custom_release_rules: bug:patch:Fixes,chore:patch:Chores,docs:patch:Documentation,feat:minor:Features,refactor:minor:Refactors,test:patch:Tests,ci:patch:Development,dev:patch:Development
24+
- name: Create Release
25+
uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0
26+
with:
27+
tag: ${{ steps.tag_version.outputs.new_tag }}
28+
name: ${{ steps.tag_version.outputs.new_tag }}
29+
body: ${{ steps.tag_version.outputs.changelog }}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: semantic-check
2+
on:
3+
pull_request:
4+
types:
5+
- opened
6+
- edited
7+
- synchronize
8+
9+
permissions:
10+
contents: read
11+
pull-requests: read
12+
13+
jobs:
14+
main:
15+
name: Semantic Commit Message Check
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout Code
19+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
20+
- uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
21+
name: Check PR for Semantic Commit Message
22+
env:
23+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24+
with:
25+
requireScope: false
26+
validateSingleCommit: true

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
!**/.gitkeep
2+
3+
tmp/
4+
dist/
5+
.DS_Store
6+
7+
.local/
8+
.env
9+
10+

Dockerfile

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
FROM golang:1.26.2-alpine AS builder
2+
3+
WORKDIR /src
4+
5+
COPY go.mod go.sum ./
6+
RUN go mod download
7+
8+
COPY . .
9+
10+
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="-s -w" -o /out/server ./cmd/server
11+
12+
FROM alpine:3.21
13+
14+
RUN adduser -D -g '' appuser
15+
16+
USER appuser
17+
WORKDIR /app
18+
19+
COPY --from=builder /out/server /app/server
20+
21+
EXPOSE 8080
22+
23+
ENTRYPOINT ["/app/server"]

Makefile

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
COMPOSE ?= docker compose
2+
3+
.PHONY: test test-unit test-integration build run docker-build up down logs demo-send demo health report
4+
5+
test:
6+
go test ./...
7+
8+
test-unit:
9+
go test ./...
10+
11+
test-integration:
12+
go test ./... -run Integration -count=1
13+
14+
build:
15+
go build ./...
16+
17+
run:
18+
go run ./cmd/server
19+
20+
docker-build:
21+
$(COMPOSE) build api
22+
23+
up:
24+
$(COMPOSE) up --build -d api
25+
26+
down:
27+
$(COMPOSE) down -v --remove-orphans
28+
29+
logs:
30+
$(COMPOSE) logs -f api
31+
32+
demo-send:
33+
$(COMPOSE) run --rm demo-sender
34+
35+
demo: up demo-send
36+
$(COMPOSE) logs api
37+
38+
health:
39+
@BASE_PATH="$${BASE_PATH:-/}"; \
40+
URL_PATH="$${BASE_PATH%/}/v1/manage/healthz"; \
41+
if [ -z "$${URL_PATH}" ]; then URL_PATH="/v1/manage/healthz"; fi; \
42+
curl -fsS "http://localhost:8080$${URL_PATH}"
43+
44+
report:
45+
@BASE_PATH="$${BASE_PATH:-/}"; \
46+
URL_PATH="$${BASE_PATH%/}/v1/reports"; \
47+
if [ -z "$${URL_PATH}" ]; then URL_PATH="/v1/reports"; fi; \
48+
curl -i -X POST \
49+
-H 'Content-Type: application/reports+json' \
50+
--data-binary @demo/reports.json \
51+
"http://localhost:8080$${URL_PATH}"

README.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,128 @@
11
# browser-reporting-api
22

33
Simple, self-hosted Go service for browser Reporting API ingestion.
4+
5+
## General
6+
7+
### What
8+
9+
`browser-reporting-api` is an HTTP service that receives browser reporting
10+
payloads (`application/reports+json` and legacy `application/csp-report` from
11+
`report-uri`), validates each report entry, and streams accepted entries to
12+
stdout as NDJSON (one JSON object per line).
13+
14+
The payload format and reporting behavior align with the browser Reporting API
15+
documented by
16+
[MDN](https://developer.mozilla.org/en-US/docs/Web/API/Reporting_API) and
17+
[Chrome](https://developer.chrome.com/docs/capabilities/web-apis/reporting-api).
18+
19+
Endpoints:
20+
21+
- `POST /v1/reports` (or `{BASE_PATH}/v1/reports`)
22+
- `GET /v1/manage/healthz`
23+
- `GET /v1/manage/readyz`
24+
25+
### Why
26+
27+
- Simple to run and reason about
28+
- Safe enough for ingestion (size limits, content-type checks, per-entry
29+
vetting)
30+
- Easy to self-host and observe (accepted reports stream to stdout)
31+
- Collected browser reports (including CSP report traffic) may support
32+
client-side monitoring and script-governance such as those relevant to PCI DSS
33+
payment-page security guidance for Requirements 6.4.3 and 11.6.1 from the
34+
[PCI Security Standards Council](https://blog.pcisecuritystandards.org/new-information-supplement-payment-page-security-and-preventing-e-skimming)
35+
36+
### How
37+
38+
Run locally with Go:
39+
40+
```bash
41+
go run ./cmd/server
42+
```
43+
44+
Run a local demo with Docker Compose:
45+
46+
```bash
47+
make demo
48+
```
49+
50+
This starts the API, sends a sample batched report payload, and prints API logs.
51+
To keep watching streamed report lines:
52+
53+
```bash
54+
make logs
55+
```
56+
57+
The demo sender payload is stored at `demo/reports.json`.
58+
59+
Send a manual sample report:
60+
61+
```bash
62+
make report
63+
```
64+
65+
`make report` sends the same payload file used by the compose demo:
66+
`demo/reports.json`.
67+
68+
Health check:
69+
70+
```bash
71+
make health
72+
```
73+
74+
Stop containers:
75+
76+
```bash
77+
make down
78+
```
79+
80+
Environment variables:
81+
82+
- `LISTEN_ADDR` (default `:8080`)
83+
- `BASE_PATH` (default `/`)
84+
- `MAX_BODY_BYTES` (default `1048576`)
85+
- `REPORTS_ALLOWED_ORIGINS` (default `*`)
86+
87+
Allowed origin examples:
88+
89+
- `REPORTS_ALLOWED_ORIGINS=*`
90+
- `REPORTS_ALLOWED_ORIGINS=https://app.example.com,https://admin.example.com`
91+
- `REPORTS_ALLOWED_ORIGINS=https://*.example.com,http://localhost:*`
92+
93+
If `BASE_PATH=/collector`, endpoints become:
94+
95+
- `POST /collector/v1/reports`
96+
- `GET /collector/v1/manage/healthz`
97+
- `GET /collector/v1/manage/readyz`
98+
99+
## Development
100+
101+
Run tests:
102+
103+
```bash
104+
go test ./...
105+
```
106+
107+
Make targets used during development:
108+
109+
```bash
110+
make test
111+
make run
112+
make up
113+
make demo-send
114+
make demo
115+
make logs
116+
make report
117+
make health
118+
make down
119+
```
120+
121+
Implementation notes:
122+
123+
- Routes are mounted under configurable `BASE_PATH`.
124+
- Reporting ingestion accepts batched arrays and processes entries
125+
independently.
126+
- Invalid entries are rejected while valid entries in the same batch are still
127+
accepted.
128+
- Accepted entries are emitted to stdout in NDJSON format.

0 commit comments

Comments
 (0)