Compare commits

..

4 Commits

Author SHA1 Message Date
Xe Iaso
e0e8a9044d Merge branch 'main' into Xe/ci-multiple-go-versions
Signed-off-by: Xe Iaso <xe.iaso@techaro.lol>
2026-03-21 19:31:02 +00:00
Jason Cameron
11c4adc6b4 fix: add cel iterator (#1465)
* fix: enable CEL iterators

Signed-off-by: Jason Cameron <jason.cameron@stanwith.me>

* test: add unit tests for CELChecker map iteration

Signed-off-by: Jason Cameron <jason.cameron@stanwith.me>

* fix: implement map iterators for HTTPHeaders and URLValues to resolve CEL internal errors

Signed-off-by: Jason Cameron <jason.cameron@stanwith.me>

* fix: replace checker.NewMapIterator with newMapIterator for HTTPHeaders and URLValues

Signed-off-by: Jason Cameron <jason.cameron@stanwith.me>

---------

Signed-off-by: Jason Cameron <jason.cameron@stanwith.me>
2026-03-21 19:30:05 +00:00
Xe Iaso
e9969ba22a chore: update spelling
check-spelling run (pull_request) for Xe/ci-multiple-go-versions

Signed-off-by: check-spelling-bot <check-spelling-bot@users.noreply.github.com>
on-behalf-of: @check-spelling <check-spelling-bot@check-spelling.dev>
2026-01-16 11:21:06 -05:00
Xe Iaso
7db2c9ebb5 ci: test against multiple go versions
Several Linux distributions and other open source package managers
build Anubis against Go oldstable. Eventually this will have to expand
to at least what FreeBSD supports. I hope they can bump the versions
of Go as soon as upstream makes new code available.

Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-01-16 11:18:31 -05:00
18 changed files with 161 additions and 48 deletions

View File

@@ -253,6 +253,7 @@ oci
OCOB
ogtag
oklch
oldstable
omgili
omgilibot
openai

View File

@@ -12,6 +12,11 @@ permissions:
jobs:
go_tests:
strategy:
matrix:
go_version:
- oldstable
- stable
#runs-on: alrest-techarohq
runs-on: ubuntu-24.04
steps:
@@ -26,10 +31,11 @@ jobs:
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: "24.11.0"
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
node-version: "latest"
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with:
go-version: "stable"
go-version: ${{ matrix.go_version }}
- name: Cache playwright binaries
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3

View File

@@ -12,7 +12,9 @@ deps:
assets: PATH:=$(PWD)/node_modules/.bin:$(PATH)
assets: deps
$(NPM) run assets
$(GO) generate ./...
./web/build.sh
./xess/build.sh
build: assets
$(GO) build -o ./var/anubis ./cmd/anubis

View File

@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed mixed tab/space indentation in Caddy documentation code block
<!-- This changes the project to: -->
- Fix CEL internal errors when iterating `headers`/`query` map wrappers by implementing map iterators for `HTTPHeaders` and `URLValues` ([#1465](https://github.com/TecharoHQ/anubis/pull/1465)).
## v1.25.0: Necron

11
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/TecharoHQ/anubis
go 1.25.0
go 1.24.2
require (
github.com/TecharoHQ/thoth-proto v0.5.0
@@ -50,7 +50,7 @@ require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.3.0 // indirect
github.com/Songmu/gitconfig v0.2.1 // indirect
github.com/TecharoHQ/yeet v0.5.0 // indirect
github.com/TecharoHQ/yeet v0.6.3 // indirect
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e // indirect
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
@@ -188,9 +188,9 @@ require (
golang.org/x/mod v0.31.0 // indirect
golang.org/x/oauth2 v0.32.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect
golang.org/x/term v0.40.0 // indirect
golang.org/x/term v0.38.0 // indirect
golang.org/x/tools v0.40.0 // indirect
golang.org/x/vuln v1.1.4 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect
@@ -198,7 +198,7 @@ require (
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
honnef.co/go/tools v0.6.1 // indirect
mvdan.cc/sh/v3 v3.13.0 // indirect
mvdan.cc/sh/v3 v3.12.0 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
)
@@ -212,5 +212,4 @@ tool (
golang.org/x/tools/cmd/stringer
golang.org/x/vuln/cmd/govulncheck
honnef.co/go/tools/cmd/staticcheck
mvdan.cc/sh/v3/cmd/gosh
)

18
go.sum
View File

@@ -31,12 +31,14 @@ github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ek
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
github.com/ProtonMail/gopenpgp/v2 v2.7.1 h1:Awsg7MPc2gD3I7IFac2qE3Gdls0lZW8SzrFZ3k1oz0s=
github.com/ProtonMail/gopenpgp/v2 v2.7.1/go.mod h1:/BU5gfAVwqyd8EfC3Eu7zmuhwYQpKs+cGD8M//iiaxs=
github.com/ProtonMail/gopenpgp/v3 v3.3.0 h1:N6rHCH5PWwB6zSRMgRj1EbAMQHUAAHxH3Oo4KibsPwY=
github.com/ProtonMail/gopenpgp/v3 v3.3.0/go.mod h1:J+iNPt0/5EO9wRt7Eit9dRUlzyu3hiGX3zId6iuaKOk=
github.com/Songmu/gitconfig v0.2.1 h1:cZsqELfMtxWVI8ovq17gbvsR4qLfoYLAiXy5GwtJWbk=
github.com/Songmu/gitconfig v0.2.1/go.mod h1:XM4O3SoXFnli9Ql2G7qXK2Fg7LJwf7Hs8GLFEOJlzmM=
github.com/TecharoHQ/thoth-proto v0.5.0 h1:Fa663s4soYiURSU8MfW9tZ2wF+LsCRSaYmjUSyagfBM=
github.com/TecharoHQ/thoth-proto v0.5.0/go.mod h1:C/U7FqTxpVn4V/qebC/GcW32I0h9xzsmWehF27KFOJs=
github.com/TecharoHQ/yeet v0.5.0 h1:6zL/9q0cnAI/79VA7fggcxDowzPA6D76I7+rvDLHNlM=
github.com/TecharoHQ/yeet v0.5.0/go.mod h1:qjWkZGADLgzB+bdm8W1GhdSBbwxVskdrvXssKraTSwQ=
github.com/TecharoHQ/yeet v0.6.3 h1:Iev6TYt/tpFYU73kbkNIYjCObYTvlihtby+htGF4Us8=
github.com/TecharoHQ/yeet v0.6.3/go.mod h1:ltt+PWPjnvmQJxEHsdJ5K9u3GoWK83vSLWCCp8XbxqI=
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e h1:HjVbSQHy+dnlS6C3XajZ69NYAb5jbGNfHanvm1+iYlo=
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e/go.mod h1:3mnrkvGpurZ4ZrTDbYU84xhwXW2TjTKShSwjRi2ihfQ=
github.com/a-h/templ v0.3.960 h1:trshEpGa8clF5cdI39iY4ZrZG8Z/QixyzEyUnA7feTM=
@@ -493,8 +495,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA=
golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -502,8 +504,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -557,8 +559,8 @@ honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI=
honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4=
k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE=
k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
mvdan.cc/sh/v3 v3.13.0 h1:dSfq/MVsY4w0Vsi6Lbs0IcQquMVqLdKLESAOZjuHdLg=
mvdan.cc/sh/v3 v3.13.0/go.mod h1:KV1GByGPc/Ho0X1E6Uz9euhsIQEj4hwyKnodLlFLoDM=
mvdan.cc/sh/v3 v3.12.0 h1:ejKUR7ONP5bb+UGHGEG/k9V5+pRVIyD+LsZz7o8KHrI=
mvdan.cc/sh/v3 v3.12.0/go.mod h1:Se6Cj17eYSn+sNooLZiEUnNNmNxg0imoYlTu4CyaGyg=
pault.ag/go/debian v0.18.0 h1:nr0iiyOU5QlG1VPnhZLNhnCcHx58kukvBJp+dvaM6CQ=
pault.ag/go/debian v0.18.0/go.mod h1:JFl0XWRCv9hWBrB5MDDZjA5GSEs1X3zcFK/9kCNIUmE=
pault.ag/go/topsort v0.1.1 h1:L0QnhUly6LmTv0e3DEzbN2q6/FGgAcQvaEw65S53Bg4=

View File

@@ -8,7 +8,7 @@ LICENSE='/*
@licstart The following is the entire license notice for the
JavaScript code in this page.
Copyright (c) 2026 Xe Iaso <xe.iaso@techaro.lol>
Copyright (c) 2025 Xe Iaso <xe.iaso@techaro.lol>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -41,9 +41,9 @@ for the JavaScript code in this page.
mkdir -p static/js
for file in js/*.tsx; do
filename="${file##*/}" # Extracts "app.jsx" from "./js/app.jsx"
output="${filename%.tsx}.js" # Changes "app.jsx" to "app.js"
echo $output
filename="${file##*/}" # Extracts "app.jsx" from "./js/app.jsx"
output="${filename%.tsx}.js" # Changes "app.jsx" to "app.js"
echo $output
esbuild "${file}" --minify --bundle --outfile=static/"${output}" --banner:js="${LICENSE}"
done
esbuild "${file}" --minify --bundle --outfile=static/"${output}" --banner:js="${LICENSE}"
done

View File

@@ -17,7 +17,7 @@ import (
"github.com/a-h/templ"
)
//go:generate go tool gosh ./build.sh
//go:generate ./build.sh
//go:generate go tool github.com/a-h/templ/cmd/templ generate
//go:embed static/app.js

View File

@@ -0,0 +1,44 @@
package policy
import (
"net/http"
"testing"
"github.com/TecharoHQ/anubis/internal/dns"
"github.com/TecharoHQ/anubis/lib/config"
"github.com/TecharoHQ/anubis/lib/store/memory"
)
func newTestDNS(t *testing.T) *dns.Dns {
t.Helper()
ctx := t.Context()
memStore := memory.New(ctx)
cache := dns.NewDNSCache(300, 300, memStore)
return dns.New(ctx, cache)
}
func TestCELChecker_MapIterationWrappers(t *testing.T) {
cfg := &config.ExpressionOrList{
Expression: `headers.exists(k, k == "Accept") && query.exists(k, k == "format")`,
}
checker, err := NewCELChecker(cfg, newTestDNS(t))
if err != nil {
t.Fatalf("creating CEL checker failed: %v", err)
}
req, err := http.NewRequest(http.MethodGet, "https://example.com/?format=json", nil)
if err != nil {
t.Fatalf("making request failed: %v", err)
}
req.Header.Set("Accept", "application/json")
got, err := checker.Check(req)
if err != nil {
t.Fatalf("checking expression failed: %v", err)
}
if !got {
t.Fatal("expected expression to evaluate true")
}
}

View File

@@ -66,7 +66,9 @@ func (h HTTPHeaders) Get(key ref.Val) ref.Val {
return result
}
func (h HTTPHeaders) Iterator() traits.Iterator { panic("TODO(Xe): implement me") }
func (h HTTPHeaders) Iterator() traits.Iterator {
return newMapIterator(h.Header)
}
func (h HTTPHeaders) IsZeroValue() bool {
return len(h.Header) == 0

View File

@@ -0,0 +1,60 @@
package expressions
import (
"errors"
"maps"
"reflect"
"slices"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
)
var ErrNotImplemented = errors.New("expressions: not implemented")
type stringSliceIterator struct {
keys []string
idx int
}
func (s *stringSliceIterator) Value() any {
return s
}
func (s *stringSliceIterator) ConvertToNative(typeDesc reflect.Type) (any, error) {
return nil, ErrNotImplemented
}
func (s *stringSliceIterator) ConvertToType(typeValue ref.Type) ref.Val {
return types.NewErr("can't convert from %q to %q", types.IteratorType, typeValue)
}
func (s *stringSliceIterator) Equal(other ref.Val) ref.Val {
return types.NewErr("can't compare %q to %q", types.IteratorType, other.Type())
}
func (s *stringSliceIterator) Type() ref.Type {
return types.IteratorType
}
func (s *stringSliceIterator) HasNext() ref.Val {
return types.Bool(s.idx < len(s.keys))
}
func (s *stringSliceIterator) Next() ref.Val {
if s.HasNext() != types.True {
return nil
}
val := s.keys[s.idx]
s.idx++
return types.String(val)
}
func newMapIterator(m map[string][]string) traits.Iterator {
return &stringSliceIterator{
keys: slices.Collect(maps.Keys(m)),
idx: 0,
}
}

View File

@@ -1,7 +1,6 @@
package expressions
import (
"errors"
"net/url"
"reflect"
"strings"
@@ -11,8 +10,6 @@ import (
"github.com/google/cel-go/common/types/traits"
)
var ErrNotImplemented = errors.New("expressions: not implemented")
// URLValues is a type wrapper to expose url.Values into CEL programs.
type URLValues struct {
url.Values
@@ -69,7 +66,9 @@ func (u URLValues) Get(key ref.Val) ref.Val {
return result
}
func (u URLValues) Iterator() traits.Iterator { panic("TODO(Xe): implement me") }
func (u URLValues) Iterator() traits.Iterator {
return newMapIterator(u.Values)
}
func (u URLValues) IsZeroValue() bool {
return len(u.Values) == 0

View File

@@ -8,7 +8,7 @@
"test:integration": "npm run assets && go test -v ./internal/test",
"test:integration:podman": "npm run assets && go test -v ./internal/test --playwright-runner=podman",
"test:integration:docker": "npm run assets && go test -v ./internal/test --playwright-runner=docker",
"assets": "go generate ./...",
"assets": "go generate ./... && ./web/build.sh && ./xess/build.sh",
"build": "npm run assets && go build -o ./var/anubis ./cmd/anubis",
"dev": "npm run assets && go run ./cmd/anubis --use-remote-address --target http://localhost:3000",
"container": "npm run assets && go run ./cmd/containerbuild",

View File

@@ -1,6 +1,6 @@
module github.com/TecharoHQ/anubis/test
go 1.25.0
go 1.24.5
replace github.com/TecharoHQ/anubis => ..
@@ -90,7 +90,7 @@ require (
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect

View File

@@ -261,8 +261,8 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=

View File

@@ -8,7 +8,7 @@ LICENSE='/*
@licstart The following is the entire license notice for the
JavaScript code in this page.
Copyright (c) 2026 Xe Iaso <xe.iaso@techaro.lol>
Copyright (c) 2025 Xe Iaso <xe.iaso@techaro.lol>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -42,15 +42,15 @@ cp ../lib/localization/locales/*.json static/locales/
shopt -s nullglob globstar
for file in js/**/*.ts js/**/*.mjs; do
out="static/${file}"
if [[ "$file" == *.ts ]]; then
out="static/${file%.ts}.mjs"
fi
out="static/${file}"
if [[ "$file" == *.ts ]]; then
out="static/${file%.ts}.mjs"
fi
mkdir -p "$(dirname "$out")"
mkdir -p "$(dirname "$out")"
esbuild "$file" --sourcemap --bundle --minify --outfile="$out" --banner:js="$LICENSE"
gzip -f -k -n "$out"
zstd -f -k --ultra -22 "$out"
brotli -fZk "$out"
esbuild "$file" --sourcemap --bundle --minify --outfile="$out" --banner:js="$LICENSE"
gzip -f -k -n "$out"
zstd -f -k --ultra -22 "$out"
brotli -fZk "$out"
done

View File

@@ -3,7 +3,6 @@ package web
import "embed"
//go:generate go tool github.com/a-h/templ/cmd/templ generate
//go:generate go tool gosh ./build.sh
var (
//go:embed static

View File

@@ -12,8 +12,6 @@ import (
"github.com/TecharoHQ/anubis/internal"
)
//go:generate go tool gosh ./build.sh
var (
//go:embed *.css static
Static embed.FS