Skip to content

Commit 84c9400

Browse files
committed
Initial commit
0 parents  commit 84c9400

31 files changed

Lines changed: 5244 additions & 0 deletions

.dockerignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Build artifacts and native libs are fetched/built inside the image.
2+
lib/
3+
bin/
4+
coverage.out
5+
*.out
6+
*.test
7+
8+
# VCS / local
9+
.git/
10+
.gitignore
11+
12+
# Docs / scratch not needed for the build
13+
*.md

.github/dependabot.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
version: 2
2+
updates:
3+
# Go module dependencies.
4+
- package-ecosystem: gomod
5+
directory: /
6+
schedule:
7+
interval: weekly
8+
9+
# GitHub Actions — keeps the SHA-pinned actions (and their version comments)
10+
# up to date.
11+
- package-ecosystem: github-actions
12+
directory: /
13+
schedule:
14+
interval: weekly
15+
16+
# Base image digests in the Dockerfiles.
17+
- package-ecosystem: docker
18+
directory: /
19+
schedule:
20+
interval: weekly
21+
- package-ecosystem: docker
22+
directory: /examples/http-gateway
23+
schedule:
24+
interval: weekly
25+
26+
# Pinned Python dependencies for the export / fixture scripts.
27+
- package-ecosystem: pip
28+
directory: /scripts
29+
schedule:
30+
interval: weekly

.github/workflows/ci.yml

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
12+
concurrency:
13+
group: ci-${{ github.ref }}
14+
cancel-in-progress: true
15+
16+
env:
17+
# cgo links the tokenizer static lib from ./lib (fetched by `make`).
18+
CGO_LDFLAGS: -L${{ github.workspace }}/lib
19+
20+
jobs:
21+
lint:
22+
runs-on: ubuntu-latest
23+
steps:
24+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
25+
26+
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
27+
with:
28+
go-version: "1.24"
29+
cache: true
30+
31+
- name: Cache native libraries
32+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
33+
with:
34+
path: lib
35+
key: native-libs-${{ runner.os }}-${{ hashFiles('Makefile') }}
36+
37+
- name: Fetch native libraries
38+
run: make libtokenizers libonnxruntime
39+
40+
- name: gofmt
41+
run: |
42+
unformatted=$(gofmt -l .)
43+
if [ -n "$unformatted" ]; then
44+
echo "These files are not gofmt-ed:"; echo "$unformatted"; exit 1
45+
fi
46+
47+
- name: go vet
48+
run: go vet ./...
49+
50+
- name: staticcheck
51+
uses: dominikh/staticcheck-action@9716614d4101e79b4340dd97b10e54d68234e431 # v1
52+
with:
53+
version: "2026.1"
54+
install-go: false
55+
56+
- name: go mod verify
57+
run: go mod verify
58+
59+
- name: govulncheck
60+
uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # v1
61+
with:
62+
go-version-input: "1.24"
63+
go-package: ./...
64+
65+
test:
66+
runs-on: ubuntu-latest
67+
steps:
68+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
69+
70+
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
71+
with:
72+
go-version: "1.24"
73+
cache: true
74+
75+
- name: Cache native libraries
76+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
77+
with:
78+
path: lib
79+
key: native-libs-${{ runner.os }}-${{ hashFiles('Makefile') }}
80+
81+
- name: Fetch native libraries
82+
run: make libtokenizers libonnxruntime
83+
84+
- name: Test (race detector)
85+
run: go test -race ./...
86+
87+
- name: Coverage
88+
run: make cover
89+
90+
- name: Upload coverage profile
91+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
92+
with:
93+
name: coverage
94+
path: coverage.out
95+
if-no-files-found: ignore
96+
97+
docker:
98+
runs-on: ubuntu-latest
99+
steps:
100+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
101+
102+
- uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
103+
104+
- name: Build daemon image (no push)
105+
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
106+
with:
107+
context: .
108+
push: false
109+
110+
- name: Build gateway image (no push)
111+
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
112+
with:
113+
context: .
114+
file: examples/http-gateway/Dockerfile
115+
push: false

.github/workflows/release.yml

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags: ["v*"]
6+
7+
permissions:
8+
contents: write # create the GitHub release
9+
packages: write # push images to GHCR
10+
11+
env:
12+
CGO_LDFLAGS: -L${{ github.workspace }}/lib
13+
14+
jobs:
15+
binaries:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
19+
20+
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
21+
with:
22+
go-version: "1.24"
23+
cache: true
24+
25+
- name: Build binaries and fetch ONNX Runtime
26+
run: make build libonnxruntime VERSION=${{ github.ref_name }}
27+
28+
- name: Package (linux-amd64)
29+
run: |
30+
version="${GITHUB_REF_NAME}"
31+
name="piguard-${version}-linux-amd64"
32+
mkdir -p "dist/${name}"
33+
cp bin/piguard bin/piguard-server lib/libonnxruntime.so README.md LICENSE "dist/${name}/"
34+
tar -C dist -czf "${name}.tar.gz" "${name}"
35+
sha256sum "${name}.tar.gz" > "${name}.tar.gz.sha256"
36+
37+
- name: Create release
38+
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
39+
with:
40+
generate_release_notes: true
41+
files: |
42+
piguard-*-linux-amd64.tar.gz
43+
piguard-*-linux-amd64.tar.gz.sha256
44+
45+
images:
46+
runs-on: ubuntu-latest
47+
steps:
48+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
49+
50+
- uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
51+
52+
- name: Log in to GHCR
53+
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
54+
with:
55+
registry: ghcr.io
56+
username: ${{ github.actor }}
57+
password: ${{ secrets.GITHUB_TOKEN }}
58+
59+
- name: Metadata (server)
60+
id: meta_server
61+
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
62+
with:
63+
images: ghcr.io/${{ github.repository }}
64+
tags: |
65+
type=semver,pattern={{version}}
66+
type=semver,pattern={{major}}.{{minor}}
67+
68+
- name: Build and push server image
69+
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
70+
with:
71+
context: .
72+
push: true
73+
tags: ${{ steps.meta_server.outputs.tags }}
74+
labels: ${{ steps.meta_server.outputs.labels }}
75+
76+
- name: Metadata (gateway)
77+
id: meta_gateway
78+
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
79+
with:
80+
images: ghcr.io/${{ github.repository }}-gateway
81+
tags: |
82+
type=semver,pattern={{version}}
83+
type=semver,pattern={{major}}.{{minor}}
84+
85+
- name: Build and push gateway image
86+
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
87+
with:
88+
context: .
89+
file: examples/http-gateway/Dockerfile
90+
push: true
91+
tags: ${{ steps.meta_gateway.outputs.tags }}
92+
labels: ${{ steps.meta_gateway.outputs.labels }}

.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Build output
2+
/bin/
3+
4+
# Native tokenizers static library (fetched via `make libtokenizers`)
5+
/lib/
6+
7+
# Go
8+
*.test
9+
*.out
10+
coverage.out
11+
12+
# Exported ONNX model (~735 MB, generated via scripts/export_onnx.py)
13+
/models/
14+
15+
# Local agent tooling
16+
/.claude/

Dockerfile

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# syntax=docker/dockerfile:1
2+
3+
# ---- build stage ----
4+
# cgo is required: the tokenizer bindings link a static library and ONNX Runtime
5+
# is loaded at runtime. A glibc base is required (the prebuilt libtokenizers.a is
6+
# a GNU build), so this uses debian-based images rather than Alpine.
7+
FROM golang:1.24-bookworm@sha256:1a6d4452c65dea36aac2e2d606b01b4a029ec90cc1ae53890540ce6173ea77ac AS builder
8+
WORKDIR /src
9+
10+
# Cache module downloads.
11+
COPY go.mod go.sum ./
12+
RUN go mod download
13+
14+
# Fetch native libs (tokenizers static + ONNX Runtime shared) and build both
15+
# binaries.
16+
COPY . .
17+
RUN make libtokenizers libonnxruntime build
18+
19+
# ---- runtime stage ----
20+
FROM debian:bookworm-slim@sha256:0104b334637a5f19aa9c983a91b54c89887c0984081f2068983107a6f6c21eeb AS runtime
21+
RUN apt-get update \
22+
&& apt-get install -y --no-install-recommends ca-certificates libstdc++6 \
23+
&& rm -rf /var/lib/apt/lists/*
24+
25+
COPY --from=builder /src/bin/piguard /usr/local/bin/piguard
26+
COPY --from=builder /src/bin/piguard-server /usr/local/bin/piguard-server
27+
COPY --from=builder /src/lib/libonnxruntime.so /usr/local/lib/libonnxruntime.so
28+
29+
# The tokenizer code is linked statically; only ONNX Runtime is loaded at
30+
# runtime, located via ORT_DYLIB_PATH.
31+
ENV ORT_DYLIB_PATH=/usr/local/lib/libonnxruntime.so
32+
33+
# Run as a non-root user. /run/piguard holds the Unix socket (share it with
34+
# clients via a volume); /models holds the exported model (mount it read-only).
35+
RUN useradd --system --uid 10001 piguard \
36+
&& mkdir -p /run/piguard /models \
37+
&& chown -R piguard /run/piguard
38+
USER piguard
39+
40+
ENTRYPOINT ["piguard-server"]
41+
CMD ["--socket", "/run/piguard/piguard.sock", "--model-dir", "/models"]

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 21no.de
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

0 commit comments

Comments
 (0)