Compare commits

...

17 Commits

Author SHA1 Message Date
Xe Iaso 8b72ded756 chore: spelling
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-04-21 15:30:49 -04:00
Xe Iaso 439860443a doc(default-config): add vague references to metrics server
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-04-21 15:28:55 -04:00
Xe Iaso 33bc4669cb doc: add metrics server configuration docs
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-04-21 15:25:19 -04:00
Xe Iaso fa5ceedf23 feat: move metrics server to a dedicated package
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-04-21 15:16:21 -04:00
Xe Iaso 49dcdbc49e fix(config): add metrics socket mode
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-04-21 15:07:08 -04:00
Xe Iaso 578f248ce1 fix(main): use internal.SetupListener
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-04-21 15:00:16 -04:00
Xe Iaso 298fc0b847 feat(internal): move SetupListener from main
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-04-21 14:57:59 -04:00
Xe Iaso 8af9845117 feat(config): add metrics bind config to policy file with flag hack
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-04-21 14:05:05 -04:00
Xe Iaso 3a6e368179 Revert "ci(ssh): enable local machines again"
This reverts commit 98afcf8c64.
2026-04-18 11:30:32 -04:00
Xe Iaso 98afcf8c64 ci(ssh): enable local machines again
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-04-18 11:22:04 -04:00
dependabot[bot] 982394ca91 build(deps): bump the github-actions group across 1 directory with 7 updates (#1560)
Co-authored-by: Jason Cameron <git@jasoncameron.dev>
2026-04-14 03:35:30 +00:00
dependabot[bot] 66b7b27aef build(deps): bump the npm group across 1 directory with 5 updates (#1559)
Co-authored-by: Jason Cameron <git@jasoncameron.dev>
2026-04-13 23:31:39 -04:00
Xe Iaso cc07be8a9e chore: spelling
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-04-10 21:40:03 -04:00
Xe Iaso 04f8b6b148 chore(sponsors): add qwertiko and wenet
Closes: #1553
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-04-10 21:36:40 -04:00
Xe Iaso dbd64e0f4f docs(faq): document minimum versions of browsers Anubis supports (#1540)
* docs(faq): document minimum versions of browsers Anubis supports

Closes: #1534
Signed-off-by: Xe Iaso <me@xeiaso.net>

* chore: update spelling

Signed-off-by: Xe Iaso <me@xeiaso.net>

---------

Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-03-24 15:59:12 +00:00
dependabot[bot] 3acf8ee387 build(deps): bump the npm group with 5 updates (#1531)
Bumps the npm group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [preact](https://github.com/preactjs/preact) | `10.28.4` | `10.29.0` |
| [@commitlint/cli](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/cli) | `20.4.3` | `20.5.0` |
| [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/config-conventional) | `20.4.3` | `20.5.0` |
| [baseline-browser-mapping](https://github.com/web-platform-dx/baseline-browser-mapping) | `2.10.0` | `2.10.8` |
| [esbuild](https://github.com/evanw/esbuild) | `0.27.3` | `0.27.4` |


Updates `preact` from 10.28.4 to 10.29.0
- [Release notes](https://github.com/preactjs/preact/releases)
- [Commits](https://github.com/preactjs/preact/compare/10.28.4...10.29.0)

Updates `@commitlint/cli` from 20.4.3 to 20.5.0
- [Release notes](https://github.com/conventional-changelog/commitlint/releases)
- [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/cli/CHANGELOG.md)
- [Commits](https://github.com/conventional-changelog/commitlint/commits/v20.5.0/@commitlint/cli)

Updates `@commitlint/config-conventional` from 20.4.3 to 20.5.0
- [Release notes](https://github.com/conventional-changelog/commitlint/releases)
- [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/config-conventional/CHANGELOG.md)
- [Commits](https://github.com/conventional-changelog/commitlint/commits/v20.5.0/@commitlint/config-conventional)

Updates `baseline-browser-mapping` from 2.10.0 to 2.10.8
- [Release notes](https://github.com/web-platform-dx/baseline-browser-mapping/releases)
- [Commits](https://github.com/web-platform-dx/baseline-browser-mapping/compare/v2.10.0...v2.10.8)

Updates `esbuild` from 0.27.3 to 0.27.4
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.27.3...v0.27.4)

---
updated-dependencies:
- dependency-name: preact
  dependency-version: 10.29.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: "@commitlint/cli"
  dependency-version: 20.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: "@commitlint/config-conventional"
  dependency-version: 20.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: baseline-browser-mapping
  dependency-version: 2.10.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: esbuild
  dependency-version: 0.27.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-24 15:54:04 +00:00
Xe Iaso 57260a562a chore(sponsors): add embeDD GmbH (#1539)
* chore(sponsors): add embeDD GmbH

Closes: #1535
Signed-off-by: Xe Iaso <me@xeiaso.net>

* chore: update spelling

Signed-off-by: Xe Iaso <me@xeiaso.net>

---------

Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-03-24 15:51:32 +00:00
67 changed files with 921 additions and 331 deletions
+4
View File
@@ -34,3 +34,7 @@ de
resourced
envoyproxy
unipromos
Samsung
wenet
qwertiko
setuplistener
+2 -4
View File
@@ -80,6 +80,7 @@ databento
dayjob
dco
DDOS
ddwrt
Debian
debrpm
decaymap
@@ -102,6 +103,7 @@ duckduckbot
eerror
ellenjoe
emacs
embe
enbyware
etld
everyones
@@ -119,7 +121,6 @@ FCr
fcrdns
fediverse
ffprobe
FFXIV
fhdr
financials
finfos
@@ -221,7 +222,6 @@ LLU
loadbalancer
lol
lominsa
maintainership
malware
mcr
memes
@@ -239,7 +239,6 @@ mymaster
mypass
myuser
nbf
Necron
nepeat
netsurf
nginx
@@ -334,7 +333,6 @@ spyderbot
srcip
srv
stackoverflow
Stargate
startprecmd
stoppostcmd
storetest
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: "24.11.0"
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "1.25.7"
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: "24.11.0"
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "stable"
+2 -2
View File
@@ -39,14 +39,14 @@ jobs:
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: "24.11.0"
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "stable"
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
- name: Log into registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Log into registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: techarohq
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
with:
persist-credentials: false
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "stable"
+2 -2
View File
@@ -27,12 +27,12 @@ jobs:
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: "24.11.0"
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "stable"
- name: Cache playwright binaries
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
id: playwright-cache
with:
path: |
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: "24.11.0"
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "stable"
@@ -29,7 +29,7 @@ jobs:
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: "24.11.0"
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "stable"
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: "24.11.0"
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "stable"
+1 -1
View File
@@ -89,7 +89,7 @@ jobs:
steps:
- name: check-spelling
id: spelling
uses: check-spelling/check-spelling@c635c2f3f714eec2fcf27b643a1919b9a811ef2e # v0.0.25
uses: check-spelling/check-spelling@cfb6f7e75bbfc89c71eaa30366d0c166f1bd9c8c # v0.0.26
with:
suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }}
checkout: true
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
fetch-depth: 0
persist-credentials: false
- name: Log into registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
+2 -2
View File
@@ -30,13 +30,13 @@ jobs:
persist-credentials: false
- name: Install CI target SSH key
uses: shimataro/ssh-key-action@6b84f2e793b32fa0b03a379cadadec75cc539391 # v2.8.0
uses: shimataro/ssh-key-action@87a8f067114a8ce263df83e9ed5c849953548bc3 # v2.8.1
with:
key: ${{ secrets.CI_SSH_KEY }}
name: id_rsa
known_hosts: ${{ secrets.CI_SSH_KNOWN_HOSTS }}
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: "stable"
+2 -2
View File
@@ -21,7 +21,7 @@ jobs:
persist-credentials: false
- name: Install the latest version of uv
uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
- name: Run zizmor 🌈
run: uvx zizmor --format sarif . > results.sarif
@@ -29,7 +29,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
with:
sarif_file: results.sarif
category: zizmor
+9
View File
@@ -73,6 +73,15 @@ Anubis is brought to you by sponsors and donors like:
<a href="https://www.anexia.com/">
<img src="./docs/static/img/sponsors/anexia-cloudsolutions-logo.webp" alt="ANEXIA Cloud Solutions" height="64">
</a>
<a href="https://dd-wrt.com/">
<img src="./docs/static/img/sponsors/ddwrt-logo.webp" alt="embeDD GmbH" height="64">
</a>
<a href="https://www.qwertiko.de?utm_campaign=github&utm_medium=referral&utm_content=anubis">
<img src="./docs/static/img/sponsors/qwertiko-logo.webp" alt="Qwertiko" height="64">
</a>
<a href="https://wenet.pl/?utm_campaign=github&utm_medium=referral&utm_content=anubis">
<img src="./docs/static/img/sponsors/wenet-logo.webp" alt="Wenet" height="64">
</a>
## Overview
+26 -130
View File
@@ -17,12 +17,10 @@ import (
"net"
"net/http"
"net/http/httputil"
"net/http/pprof"
"net/url"
"os"
"os/signal"
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
@@ -33,12 +31,12 @@ import (
"github.com/TecharoHQ/anubis/internal"
libanubis "github.com/TecharoHQ/anubis/lib"
"github.com/TecharoHQ/anubis/lib/config"
"github.com/TecharoHQ/anubis/lib/metrics"
botPolicy "github.com/TecharoHQ/anubis/lib/policy"
"github.com/TecharoHQ/anubis/lib/thoth"
"github.com/TecharoHQ/anubis/web"
"github.com/facebookgo/flagenv"
_ "github.com/joho/godotenv/autoload"
"github.com/prometheus/client_golang/prometheus/promhttp"
healthv1 "google.golang.org/grpc/health/grpc_health_v1"
)
@@ -119,33 +117,6 @@ func doHealthCheck() error {
return nil
}
// parseBindNetFromAddr determine bind network and address based on the given network and address.
func parseBindNetFromAddr(address string) (string, string) {
defaultScheme := "http://"
if !strings.Contains(address, "://") {
if strings.HasPrefix(address, ":") {
address = defaultScheme + "localhost" + address
} else {
address = defaultScheme + address
}
}
bindUri, err := url.Parse(address)
if err != nil {
log.Fatal(fmt.Errorf("failed to parse bind URL: %w", err))
}
switch bindUri.Scheme {
case "unix":
return "unix", bindUri.Path
case "tcp", "http", "https":
return "tcp", bindUri.Host
default:
log.Fatal(fmt.Errorf("unsupported network scheme %s in address %s", bindUri.Scheme, address))
}
return "", address
}
func parseSameSite(s string) http.SameSite {
switch strings.ToLower(s) {
case "none":
@@ -162,53 +133,6 @@ func parseSameSite(s string) http.SameSite {
return http.SameSiteDefaultMode
}
func setupListener(network string, address string) (net.Listener, string) {
formattedAddress := ""
if network == "" {
// keep compatibility
network, address = parseBindNetFromAddr(address)
}
switch network {
case "unix":
formattedAddress = "unix:" + address
case "tcp":
if strings.HasPrefix(address, ":") { // assume it's just a port e.g. :4259
formattedAddress = "http://localhost" + address
} else {
formattedAddress = "http://" + address
}
default:
formattedAddress = fmt.Sprintf(`(%s) %s`, network, address)
}
listener, err := net.Listen(network, address)
if err != nil {
log.Fatal(fmt.Errorf("failed to bind to %s: %w", formattedAddress, err))
}
// additional permission handling for unix sockets
if network == "unix" {
mode, err := strconv.ParseUint(*socketMode, 8, 0)
if err != nil {
listener.Close()
log.Fatal(fmt.Errorf("could not parse socket mode %s: %w", *socketMode, err))
}
err = os.Chmod(address, os.FileMode(mode))
if err != nil {
err := listener.Close()
if err != nil {
log.Printf("failed to close listener: %v", err)
}
log.Fatal(fmt.Errorf("could not change socket mode: %w", err))
}
}
return listener, formattedAddress
}
func makeReverseProxy(target string, targetSNI string, targetHost string, insecureSkipVerify bool, targetDisableKeepAlive bool) (http.Handler, error) {
targetUri, err := url.Parse(target)
if err != nil {
@@ -304,11 +228,6 @@ func main() {
wg := new(sync.WaitGroup)
if *metricsBind != "" {
wg.Add(1)
go metricsServer(ctx, *lg.With("subsystem", "metrics"), wg.Done)
}
var rp http.Handler
// when using anubis via Systemd and environment variables, then it is not possible to set targe to an empty string but only to space
if strings.TrimSpace(*target) != "" {
@@ -348,6 +267,26 @@ func main() {
lg.Debug("swapped to new logger")
slog.SetDefault(lg)
if *metricsBind != "" || policy.Metrics != nil {
wg.Add(1)
ms := &metrics.Server{
Config: policy.Metrics,
Log: lg,
}
if policy.Metrics == nil {
lg.Debug("migrating flags to metrics config", "bind", *metricsBind, "network", *metricsBindNetwork, "socket-mode", *socketMode)
ms.Config = &config.Metrics{
Bind: *metricsBind,
Network: *metricsBindNetwork,
SocketMode: *socketMode,
}
}
go ms.Run(ctx, wg.Done)
}
// Warn if persistent storage is used without a configured signing key
if policy.Store.IsPersistent() {
if *hs512Secret == "" && *ed25519PrivateKeyHex == "" && *ed25519PrivateKeyHexFile == "" {
@@ -484,7 +423,11 @@ func main() {
h = internal.JA4H(h)
srv := http.Server{Handler: h, ErrorLog: internal.GetFilteredHTTPLogger()}
listener, listenerUrl := setupListener(*bindNetwork, *bind)
listener, listenerUrl, err := internal.SetupListener(*bindNetwork, *bind, *socketMode)
if err != nil {
log.Fatalf("SetupListener(%q, %q, %q): %v", *bindNetwork, *bind, *socketMode, err)
}
lg.Info(
"listening",
"url", listenerUrl,
@@ -519,53 +462,6 @@ func main() {
wg.Wait()
}
func metricsServer(ctx context.Context, lg slog.Logger, done func()) {
defer done()
mux := http.NewServeMux()
mux.HandleFunc("GET /debug/pprof/", pprof.Index)
mux.HandleFunc("GET /debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("GET /debug/pprof/profile", pprof.Profile)
mux.HandleFunc("GET /debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("GET /debug/pprof/trace", pprof.Trace)
mux.Handle("/metrics", promhttp.Handler())
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
st, ok := internal.GetHealth("anubis")
if !ok {
slog.Error("health service anubis does not exist, file a bug")
}
switch st {
case healthv1.HealthCheckResponse_NOT_SERVING:
http.Error(w, "NOT OK", http.StatusInternalServerError)
return
case healthv1.HealthCheckResponse_SERVING:
fmt.Fprintln(w, "OK")
return
default:
http.Error(w, "UNKNOWN", http.StatusFailedDependency)
return
}
})
srv := http.Server{Handler: mux, ErrorLog: internal.GetFilteredHTTPLogger()}
listener, metricsUrl := setupListener(*metricsBindNetwork, *metricsBind)
lg.Debug("listening for metrics", "url", metricsUrl)
go func() {
<-ctx.Done()
c, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(c); err != nil {
log.Printf("cannot shut down: %v", err)
}
}()
if err := srv.Serve(listener); !errors.Is(err, http.ErrServerClosed) {
log.Fatal(err)
}
}
func extractEmbedFS(fsys embed.FS, root string, destDir string) error {
return fs.WalkDir(fsys, root, func(path string, d fs.DirEntry, err error) error {
if err != nil {
+9
View File
@@ -166,6 +166,15 @@ status_codes:
CHALLENGE: 200
DENY: 200
# # Configuration for the metrics server. See the docs for more information:
# #
# # https://anubis.techaro.lol/docs/admin/policies#metrics-server
# #
# # This is commented out by default so that command line flags take precedence.
# metrics:
# bind: ":9090"
# network: "tcp"
# Anubis can store temporary data in one of a few backends. See the storage
# backends section of the docs for more information:
#
+3 -2
View File
@@ -11,14 +11,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
<!-- This changes the project to: -->
- Move metrics server configuration to [the policy file](./admin/policies.mdx#metrics-server).
- Expose [pprof endpoints](https://pkg.go.dev/net/http/pprof) on the metrics listener to enable profiling Anubis in production.
- fix: prevent nil pointer panic in challenge validation when threshold rules match during PassChallenge (#1463)
- Instruct reverse proxies to not cache error pages.
- Fixed mixed tab/space indentation in Caddy documentation code block
- Improve error messages and fix broken REDIRECT_DOMAINS link in docs ([#1193](https://github.com/TecharoHQ/anubis/issues/1193))
- Add Bulgarian locale ([#1394](https://github.com/TecharoHQ/anubis/pull/1394))
<!-- 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
+3 -3
View File
@@ -87,15 +87,15 @@ Anubis uses these environment variables for configuration:
| `ED25519_PRIVATE_KEY_HEX_FILE` | unset | Path to a file containing the hex-encoded ed25519 private key. Only one of this or its sister option may be set. **Required when using persistent storage backends** (like bbolt) to ensure challenges survive service restarts. When running multiple instances on the same base domain, the key must be the same across all instances. |
| `ERROR_TITLE` | unset | <EO /> If set, override the translation stack to show a custom title for error pages such as "Something went wrong!". See [Customizing messages](./botstopper.mdx#customizing-messages) for more details. |
| `JWT_RESTRICTION_HEADER` | `X-Real-IP` | If set, the JWT is only valid if the current value of this header matches the value when the JWT was created. You can use it e.g. to restrict a JWT to the source IP of the user using `X-Real-IP`. |
| `METRICS_BIND` | `:9090` | The network address that Anubis serves Prometheus metrics on. See `BIND` for more information. |
| `METRICS_BIND_NETWORK` | `tcp` | The address family that the Anubis metrics server listens on. See `BIND_NETWORK` for more information. |
| `METRICS_BIND` | `:9090` | The legacy configuration value for the network address that Anubis serves Prometheus metrics on. Please migrate this to [the policy file](./policies.mdx#metrics-server) as soon as possible. |
| `METRICS_BIND_NETWORK` | `tcp` | The legacy configuration value for the address family that Anubis serves Prometheus metrics on. Please migrate this to [the policy file](./policies.mdx#metrics-server) as soon as possible. |
| `OG_EXPIRY_TIME` | `24h` | The expiration time for the Open Graph tag cache. Prefer using [the policy file](./configuration/open-graph.mdx) to configure the Open Graph subsystem. |
| `OG_PASSTHROUGH` | `false` | If set to `true`, Anubis will enable Open Graph tag passthrough. Prefer using [the policy file](./configuration/open-graph.mdx) to configure the Open Graph subsystem. |
| `OG_CACHE_CONSIDER_HOST` | `false` | If set to `true`, Anubis will consider the host in the Open Graph tag cache key. Prefer using [the policy file](./configuration/open-graph.mdx) to configure the Open Graph subsystem. |
| `OVERLAY_FOLDER` | unset | <EO /> If set, treat the given path as an [overlay folder](./botstopper.mdx#custom-images-and-css), allowing you to customize CSS, fonts, images, and add other assets to BotStopper deployments. |
| `POLICY_FNAME` | unset | The file containing [bot policy configuration](./policies.mdx). See the bot policy documentation for more details. If unset, the default bot policy configuration is used. |
| `PUBLIC_URL` | unset | The externally accessible URL for this Anubis instance, used for constructing redirect URLs (e.g., for Traefik forwardAuth). Leave it unset when Anubis terminates traffic directly (sidecar/standalone deployments) or redirect building will fail with `redir=null`. |
| `REDIRECT_DOMAINS` | unset | Comma-separated list of domain names that Anubis should allow redirects to when passing a challenge. See [Redirect Domain Configuration](./configuration/redirect-domains.mdx) for more details. |
| `REDIRECT_DOMAINS` | unset | Comma-separated list of domain names that Anubis should allow redirects to when passing a challenge. See [Redirect Domain Configuration](./configuration/redirect-domains.mdx) for more details. |
| `SERVE_ROBOTS_TXT` | `false` | If set `true`, Anubis will serve a default `robots.txt` file that disallows all known AI scrapers by name and then additionally disallows every scraper. This is useful if facts and circumstances make it difficult to change the underlying service to serve such a `robots.txt` file. |
| `SLOG_LEVEL` | `INFO` | The log level for structured logging. Valid values are `DEBUG`, `INFO`, `WARN`, and `ERROR`. Set to `DEBUG` to see all requests, evaluations, and detailed diagnostic information. |
| `SOCKET_MODE` | `0770` | _Only used when at least one of the `*_BIND_NETWORK` variables are set to `unix`._ The socket mode (permissions) for Unix domain sockets. |
+21
View File
@@ -117,6 +117,27 @@ remote_addresses:
- 100.64.0.0/10
```
## Metrics server
Anubis includes support for [Prometheus-style metrics](https://prometheus.io/docs/introduction/overview/), allowing systems administrators to monitor Anubis' performance and effectiveness. This is a separate HTTP server with metrics, health checking, and debug routes.
Anubis' metrics server is configured with the `metrics` block in the configuration file:
```yaml
metrics:
bind: ":9090"
network: "tcp"
```
If you want to bind metrics to a Unix socket, make sure to set the network to `unix` and add a socket mode:
```yaml
metrics:
bind: "/tmp/anubis_metrics.sock"
network: unix
socketMode: "0700" # must be a string
```
## Imprint / Impressum support
Anubis has support for showing imprint / impressum information. This is defined in the `impressum` block of your configuration. See [Imprint / Impressum configuration](./configuration/impressum.mdx) for more information.
+9
View File
@@ -87,6 +87,15 @@ Anubis is brought to you by sponsors and donors like:
height="64"
/>
</a>
<a href="https://dd-wrt.com/">
<img src="/img/sponsors/ddwrt-logo.webp" alt="embeDD GmbH" height="64" />
</a>
<a href="https://www.qwertiko.de?utm_campaign=github&utm_medium=referral&utm_content=anubis">
<img src="/img/sponsors/qwertiko-logo.webp" alt="Qwertiko" height="64" />
</a>
<a href="https://wenet.pl/?utm_campaign=github&utm_medium=referral&utm_content=anubis">
<img src="/img/sponsors/wenet-logo.webp" alt="Wenet" height="64" />
</a>
## Overview
@@ -32,3 +32,14 @@ This interpreter is much slower than native code because it has to translate eac
Some users choose to disable JIT as a hardening measure against theoretical browser exploits. This is a reasonable choice if you face targeted attacks from well-resourced adversaries (such as nation-state actors), but it comes with real performance costs.
If you've disabled JIT and find Anubis checks slow, re-enabling JIT is the fix. There is no way for Anubis to work around this on our end.
## What versions of browsers does Anubis support?
Anubis is written mainly by a single person in a basement in Canada. As such it is impossible for Anubis to support every version of every browser on the planet. As such, here's a few rules of thumb for the browsers that Anubis focuses on supporting:
- At least the two (2) most recent LTS releases of Firefox and Chrome.
- At least the version of Chromium as used by the Samsung Browser on Android.
- At least the last version of Chromium and Firefox that are known to run on Windows 7.
- At least the version of Safari that runs on the second-to-oldest iPhone model currently on the market.
We cannot give more cohesive version bounds than this. If you run into problems, please file an issue. Sometimes you may just need to upgrade hardware though.
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

+92
View File
@@ -0,0 +1,92 @@
package internal
import (
"errors"
"fmt"
"net"
"net/url"
"os"
"strconv"
"strings"
)
// parseBindNetFromAddr determine bind network and address based on the given network and address.
func parseBindNetFromAddr(address string) (string, string, error) {
defaultScheme := "http://"
if !strings.Contains(address, "://") {
if strings.HasPrefix(address, ":") {
address = defaultScheme + "localhost" + address
} else {
address = defaultScheme + address
}
}
bindUri, err := url.Parse(address)
if err != nil {
return "", "", fmt.Errorf("failed to parse bind URL: %w", err)
}
switch bindUri.Scheme {
case "unix":
return "unix", bindUri.Path, nil
case "tcp", "http", "https":
return "tcp", bindUri.Host, nil
default:
return "", "", fmt.Errorf("unsupported network scheme %s in address %s", bindUri.Scheme, address)
}
}
// SetupListener sets up a network listener based on the input from configuration
// envvars. It returns a network listener and the URL to that listener or an error.
func SetupListener(network, address, socketMode string) (net.Listener, string, error) {
formattedAddress := ""
var err error
if network == "" {
// keep compatibility
network, address, err = parseBindNetFromAddr(address)
}
if err != nil {
return nil, "", fmt.Errorf("can't parse bind and network: %w", err)
}
switch network {
case "unix":
formattedAddress = "unix:" + address
case "tcp":
if strings.HasPrefix(address, ":") { // assume it's just a port e.g. :4259
formattedAddress = "http://localhost" + address
} else {
formattedAddress = "http://" + address
}
default:
formattedAddress = fmt.Sprintf(`(%s) %s`, network, address)
}
ln, err := net.Listen(network, address)
if err != nil {
return nil, "", fmt.Errorf("failed to bind to %s: %w", formattedAddress, err)
}
// additional permission handling for unix sockets
if network == "unix" {
mode, err := strconv.ParseUint(socketMode, 8, 0)
if err != nil {
ln.Close()
return nil, "", fmt.Errorf("could not parse socket mode %s: %w", socketMode, err)
}
err = os.Chmod(address, os.FileMode(mode))
if err != nil {
err := fmt.Errorf("could not change socket mode: %w", err)
clErr := ln.Close()
if clErr != nil {
return nil, "", errors.Join(err, clErr)
}
return nil, "", err
}
}
return ln, formattedAddress, nil
}
+180
View File
@@ -0,0 +1,180 @@
package internal
import (
"io/fs"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
)
func TestParseBindNetFromAddr(t *testing.T) {
for _, tt := range []struct {
name string
address string
wantErr bool
network string
bind string
}{
{
name: "simple tcp",
address: "localhost:9090",
wantErr: false,
network: "tcp",
bind: "localhost:9090",
},
{
name: "simple unix",
address: "unix:///tmp/foo.sock",
wantErr: false,
network: "unix",
bind: "/tmp/foo.sock",
},
{
name: "invalid network",
address: "foo:///tmp/bar.sock",
wantErr: true,
},
{
name: "tcp uri",
address: "tcp://[::]:9090",
wantErr: false,
network: "tcp",
bind: "[::]:9090",
},
{
name: "http uri",
address: "http://[::]:9090",
wantErr: false,
network: "tcp",
bind: "[::]:9090",
},
{
name: "https uri",
address: "https://[::]:9090",
wantErr: false,
network: "tcp",
bind: "[::]:9090",
},
} {
t.Run(tt.name, func(t *testing.T) {
network, bind, err := parseBindNetFromAddr(tt.address)
switch {
case tt.wantErr && err == nil:
t.Errorf("parseBindNetFromAddr(%q) should have errored but did not", tt.address)
case !tt.wantErr && err != nil:
t.Errorf("parseBindNetFromAddr(%q) threw an error: %v", tt.address, err)
}
if network != tt.network {
t.Errorf("parseBindNetFromAddr(%q) wanted network: %q, got: %q", tt.address, tt.network, network)
}
if bind != tt.bind {
t.Errorf("parseBindNetFromAddr(%q) wanted bind: %q, got: %q", tt.address, tt.bind, bind)
}
})
}
}
func TestSetupListener(t *testing.T) {
td := t.TempDir()
for _, tt := range []struct {
name string
network, address, socketMode string
wantErr bool
socketURLPrefix string
}{
{
name: "simple tcp",
network: "",
address: ":0",
wantErr: false,
socketURLPrefix: "http://localhost:",
},
{
name: "simple unix",
network: "",
address: "unix://" + filepath.Join(td, "a"),
socketMode: "0770",
wantErr: false,
socketURLPrefix: "unix:" + filepath.Join(td, "a"),
},
{
name: "tcp",
network: "tcp",
address: ":0",
wantErr: false,
socketURLPrefix: "http://localhost:",
},
{
name: "udp",
network: "udp",
address: ":0",
wantErr: true,
socketURLPrefix: "http://localhost:",
},
{
name: "unix socket",
network: "unix",
socketMode: "0770",
address: filepath.Join(td, "a"),
wantErr: false,
socketURLPrefix: "unix:" + filepath.Join(td, "a"),
},
{
name: "invalid socket mode",
network: "unix",
socketMode: "taco bell",
address: filepath.Join(td, "a"),
wantErr: true,
socketURLPrefix: "unix:" + filepath.Join(td, "a"),
},
{
name: "empty socket mode",
network: "unix",
socketMode: "",
address: filepath.Join(td, "a"),
wantErr: true,
socketURLPrefix: "unix:" + filepath.Join(td, "a"),
},
} {
t.Run(tt.name, func(t *testing.T) {
ln, socketURL, err := SetupListener(tt.network, tt.address, tt.socketMode)
switch {
case tt.wantErr && err == nil:
t.Errorf("SetupListener(%q, %q, %q) should have errored but did not", tt.network, tt.address, tt.socketMode)
case !tt.wantErr && err != nil:
t.Fatalf("SetupListener(%q, %q, %q) threw an error: %v", tt.network, tt.address, tt.socketMode, err)
}
if ln != nil {
defer ln.Close()
}
if !tt.wantErr && !strings.HasPrefix(socketURL, tt.socketURLPrefix) {
t.Errorf("SetupListener(%q, %q, %q) should have returned a URL with prefix %q but got: %q", tt.network, tt.address, tt.socketMode, tt.socketURLPrefix, socketURL)
}
if tt.socketMode != "" {
mode, err := strconv.ParseUint(tt.socketMode, 8, 0)
if err != nil {
return
}
sockPath := strings.TrimPrefix(socketURL, "unix:")
st, err := os.Stat(sockPath)
if err != nil {
t.Fatalf("can't os.Stat(%q): %v", sockPath, err)
}
if st.Mode().Perm() != fs.FileMode(mode) {
t.Errorf("file mode of %q should be %s but is actually %s", sockPath, strconv.FormatUint(mode, 8), strconv.FormatUint(uint64(st.Mode()), 8))
}
}
})
}
}
+9
View File
@@ -334,6 +334,7 @@ type fileConfig struct {
DNSBL bool `json:"dnsbl"`
DNSTTL DnsTTL `json:"dns_ttl"`
Logging *Logging `json:"logging"`
Metrics *Metrics `json:"metrics,omitempty"`
}
func (c *fileConfig) Valid() error {
@@ -375,6 +376,12 @@ func (c *fileConfig) Valid() error {
}
}
if c.Metrics != nil {
if err := c.Metrics.Valid(); err != nil {
errs = append(errs, err)
}
}
if len(errs) != 0 {
return fmt.Errorf("config is not valid:\n%w", errors.Join(errs...))
}
@@ -417,6 +424,7 @@ func Load(fin io.Reader, fname string) (*Config, error) {
StatusCodes: c.StatusCodes,
Store: c.Store,
Logging: c.Logging,
Metrics: c.Metrics,
}
if c.OpenGraph.TimeToLive != "" {
@@ -508,6 +516,7 @@ type Config struct {
Logging *Logging
DNSBL bool
DNSTTL DnsTTL
Metrics *Metrics
}
func (c Config) Valid() error {
+54
View File
@@ -0,0 +1,54 @@
package config
import (
"errors"
"fmt"
"strconv"
)
var (
ErrInvalidMetricsConfig = errors.New("config: invalid metrics configuration")
ErrNoMetricsBind = errors.New("config.Metrics: must define bind")
ErrNoMetricsNetwork = errors.New("config.Metrics: must define network")
ErrNoMetricsSocketMode = errors.New("config.Metrics: must define socket mode when using unix sockets")
ErrInvalidMetricsSocketMode = errors.New("config.Metrics: invalid unix socket mode")
ErrInvalidMetricsNetwork = errors.New("config.Metrics: invalid metrics network")
)
type Metrics struct {
Bind string `json:"bind" yaml:"bind"`
Network string `json:"network" yaml:"network"`
SocketMode string `json:"socketMode" yaml:"socketMode"`
}
func (m *Metrics) Valid() error {
var errs []error
if m.Bind == "" {
errs = append(errs, ErrNoMetricsBind)
}
if m.Network == "" {
errs = append(errs, ErrNoMetricsNetwork)
}
switch m.Network {
case "tcp", "tcp4", "tcp6": // https://pkg.go.dev/net#Listen
case "unix":
if m.SocketMode == "" {
errs = append(errs, ErrNoMetricsSocketMode)
}
if _, err := strconv.ParseUint(m.SocketMode, 8, 0); err != nil {
errs = append(errs, fmt.Errorf("%w: %w", ErrInvalidMetricsSocketMode, err))
}
default:
errs = append(errs, ErrInvalidMetricsNetwork)
}
if len(errs) != 0 {
return errors.Join(ErrInvalidMetricsConfig, errors.Join(errs...))
}
return nil
}
+87
View File
@@ -0,0 +1,87 @@
package config
import (
"errors"
"testing"
)
func TestMetricsValid(t *testing.T) {
for _, tt := range []struct {
name string
input *Metrics
err error
}{
{
name: "basic TCP",
input: &Metrics{
Bind: ":9090",
Network: "tcp",
},
},
{
name: "basic TCP4",
input: &Metrics{
Bind: ":9090",
Network: "tcp4",
},
},
{
name: "basic TCP6",
input: &Metrics{
Bind: ":9090",
Network: "tcp6",
},
},
{
name: "basic unix",
input: &Metrics{
Bind: "/tmp/anubis-metrics.sock",
Network: "unix",
SocketMode: "0770",
},
},
{
name: "no bind",
input: &Metrics{},
err: ErrNoMetricsBind,
},
{
name: "no network",
input: &Metrics{},
err: ErrNoMetricsNetwork,
},
{
name: "no unix socket mode",
input: &Metrics{
Bind: "/tmp/anubis-metrics.sock",
Network: "unix",
},
err: ErrNoMetricsSocketMode,
},
{
name: "invalid unix socket mode",
input: &Metrics{
Bind: "/tmp/anubis-metrics.sock",
Network: "unix",
SocketMode: "taco bell",
},
err: ErrInvalidMetricsSocketMode,
},
{
name: "invalid network",
input: &Metrics{
Bind: ":9090",
Network: "taco",
},
err: ErrInvalidMetricsNetwork,
},
} {
t.Run(tt.name, func(t *testing.T) {
if err := tt.input.Valid(); !errors.Is(err, tt.err) {
t.Logf("wanted error: %v", tt.err)
t.Logf("got error: %v", err)
t.Error("validation failed")
}
})
}
}
+3
View File
@@ -0,0 +1,3 @@
metrics:
bind: ":9090"
network: taco
+5 -1
View File
@@ -5,5 +5,9 @@
"remote_addresses": ["0.0.0.0/0", "::/0"],
"action": "ALLOW"
}
]
],
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -4,3 +4,7 @@ bots:
- "0.0.0.0/0"
- "::/0"
action: ALLOW
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -8,5 +8,9 @@
"action": "DENY"
}
],
"dnsbl": false
"dnsbl": false,
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -3,3 +3,7 @@ bots:
headers_regex:
CF-Worker: .*
action: DENY
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -4,3 +4,7 @@ bots:
asns:
match:
- 13335 # Cloudflare
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -5,5 +5,9 @@
"user_agent_regex": "Mozilla",
"action": "CHALLENGE"
}
]
],
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -2,3 +2,7 @@ bots:
- name: generic-browser
user_agent_regex: Mozilla
action: CHALLENGE
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -6,3 +6,7 @@ bots:
- name: "test"
user_agent_regex: ".*"
action: "DENY"
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -6,3 +6,7 @@ bots:
- '"Accept" in headers'
- headers["Accept"].contains("text/html")
- randInt(1) == 0
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -6,5 +6,9 @@
"action": "DENY"
}
],
"dnsbl": false
"dnsbl": false,
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -2,3 +2,7 @@ bots:
- name: everything
user_agent_regex: .*
action: DENY
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -4,3 +4,7 @@ bots:
geoip:
countries:
- US
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -10,5 +10,9 @@
]
}
}
]
],
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -6,3 +6,7 @@ bots:
- userAgent.startsWith("git/") || userAgent.contains("libgit")
- >
"Git-Protocol" in headers && headers["Git-Protocol"] == "version=2"
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -3,5 +3,9 @@
{
"import": "./testdata/hack-test.json"
}
]
],
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -1,2 +1,6 @@
bots:
- import: ./testdata/hack-test.yaml
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -3,5 +3,9 @@
{
"import": "(data)/common/keep-internet-working.yaml"
}
]
],
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
@@ -1,2 +1,6 @@
bots:
- import: (data)/common/keep-internet-working.yaml
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -8,3 +8,7 @@ impressum:
page:
title: Test
body: <p>This is a test</p>
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -13,3 +13,7 @@ logs:
oldFileTimeFormat: 2006-01-02T15-04-05 # RFC 3339-ish
compress: true
useLocalTime: false # timezone for rotated files is UTC
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -5,3 +5,7 @@ bots:
logging:
sink: "stdio"
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -6,3 +6,7 @@ bots:
adjust: 5
thresholds: []
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -75,5 +75,9 @@
"user_agent_regex": "Mozilla",
"action": "CHALLENGE"
}
]
],
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -10,3 +10,7 @@ openGraph:
default:
"og:title": "Xe's magic land of fun"
"og:description": "We're no strangers to love, you know the rules and so do I"
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -4,3 +4,7 @@ bots:
user_agent_regex: Mozilla
weight:
adjust: 5
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -9,5 +9,9 @@
"status_codes": {
"CHALLENGE": 200,
"DENY": 200
},
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -6,3 +6,7 @@ bots:
status_codes:
CHALLENGE: 200
DENY: 200
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -9,5 +9,9 @@
"status_codes": {
"CHALLENGE": 403,
"DENY": 403
},
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -6,3 +6,7 @@ bots:
status_codes:
CHALLENGE: 403
DENY: 403
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -33,3 +33,7 @@ thresholds:
challenge:
algorithm: fast
difficulty: 4
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -2,3 +2,7 @@ bots:
- name: weight
action: WEIGH
user_agent_regex: Mozilla
metrics:
bind: ":9090"
network: "tcp"
+81
View File
@@ -0,0 +1,81 @@
package metrics
import (
"context"
"errors"
"fmt"
"log/slog"
"net/http"
"net/http/pprof"
"time"
"github.com/TecharoHQ/anubis/internal"
"github.com/TecharoHQ/anubis/lib/config"
"github.com/prometheus/client_golang/prometheus/promhttp"
healthv1 "google.golang.org/grpc/health/grpc_health_v1"
)
type Server struct {
Config *config.Metrics
Log *slog.Logger
}
func (s *Server) Run(ctx context.Context, done func()) error {
defer done()
lg := s.Log.With("subsystem", "metrics")
mux := http.NewServeMux()
mux.HandleFunc("GET /debug/pprof/", pprof.Index)
mux.HandleFunc("GET /debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("GET /debug/pprof/profile", pprof.Profile)
mux.HandleFunc("GET /debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("GET /debug/pprof/trace", pprof.Trace)
mux.Handle("/metrics", promhttp.Handler())
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
st, ok := internal.GetHealth("anubis")
if !ok {
slog.Error("health service anubis does not exist, file a bug")
}
switch st {
case healthv1.HealthCheckResponse_NOT_SERVING:
http.Error(w, "NOT OK", http.StatusInternalServerError)
return
case healthv1.HealthCheckResponse_SERVING:
fmt.Fprintln(w, "OK")
return
default:
http.Error(w, "UNKNOWN", http.StatusFailedDependency)
return
}
})
srv := http.Server{
Handler: mux,
ErrorLog: internal.GetFilteredHTTPLogger(),
}
ln, metricsURL, err := internal.SetupListener(s.Config.Bind, s.Config.Network, s.Config.SocketMode)
if err != nil {
return fmt.Errorf("can't setup listener: %w", err)
}
defer ln.Close()
lg.Debug("listening for metrics", "url", metricsURL)
go func() {
<-ctx.Done()
c, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(c); err != nil {
lg.Error("can't shut down metrics server", "err", err)
}
}()
if err := srv.Serve(ln); !errors.Is(err, http.ErrServerClosed) {
return fmt.Errorf("can't serve metrics server: %w", err)
}
return nil
}
+2
View File
@@ -46,6 +46,7 @@ type ParsedConfig struct {
DnsCache *dns.DnsCache
Dns *dns.Dns
Logger *slog.Logger
Metrics *config.Metrics
}
func newParsedConfig(orig *config.Config) *ParsedConfig {
@@ -53,6 +54,7 @@ func newParsedConfig(orig *config.Config) *ParsedConfig {
orig: orig,
OpenGraph: orig.OpenGraph,
StatusCodes: orig.StatusCodes,
Metrics: orig.Metrics,
}
}
+160 -160
View File
@@ -10,15 +10,15 @@
"license": "ISC",
"dependencies": {
"@aws-crypto/sha256-js": "^5.2.0",
"preact": "^10.28.4"
"preact": "^10.29.1"
},
"devDependencies": {
"@commitlint/cli": "^20.4.3",
"@commitlint/config-conventional": "^20.4.3",
"baseline-browser-mapping": "^2.10.0",
"cssnano": "^7.1.3",
"cssnano-preset-advanced": "^7.0.11",
"esbuild": "^0.27.3",
"@commitlint/cli": "^20.5.0",
"@commitlint/config-conventional": "^20.5.0",
"baseline-browser-mapping": "^2.10.15",
"cssnano": "^7.1.4",
"cssnano-preset-advanced": "^7.0.12",
"esbuild": "^0.28.0",
"husky": "^9.1.7",
"playwright": "^1.52.0",
"postcss-cli": "^11.0.1",
@@ -91,18 +91,25 @@
"node": ">=6.9.0"
}
},
"node_modules/@colordx/core": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@colordx/core/-/core-5.0.3.tgz",
"integrity": "sha512-xBQ0MYRTNNxW3mS2sJtlQTT7C3Sasqgh1/PsHva7fyDb5uqYY+gv9V0utDdX8X80mqzbGz3u/IDJdn2d/uW09g==",
"dev": true,
"license": "MIT"
},
"node_modules/@commitlint/cli": {
"version": "20.4.3",
"resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.4.3.tgz",
"integrity": "sha512-Z37EMoDT7+Upg500vlr/vZrgRsb6Xc5JAA3Tv7BYbobnN/ZpqUeZnSLggBg2+1O+NptRDtyujr2DD1CPV2qwhA==",
"version": "20.5.0",
"resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.5.0.tgz",
"integrity": "sha512-yNkyN/tuKTJS3wdVfsZ2tXDM4G4Gi7z+jW54Cki8N8tZqwKBltbIvUUrSbT4hz1bhW/h0CdR+5sCSpXD+wMKaQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@commitlint/format": "^20.4.3",
"@commitlint/lint": "^20.4.3",
"@commitlint/load": "^20.4.3",
"@commitlint/read": "^20.4.3",
"@commitlint/types": "^20.4.3",
"@commitlint/format": "^20.5.0",
"@commitlint/lint": "^20.5.0",
"@commitlint/load": "^20.5.0",
"@commitlint/read": "^20.5.0",
"@commitlint/types": "^20.5.0",
"tinyexec": "^1.0.0",
"yargs": "^17.0.0"
},
@@ -114,13 +121,13 @@
}
},
"node_modules/@commitlint/config-conventional": {
"version": "20.4.3",
"resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.4.3.tgz",
"integrity": "sha512-9RtLySbYQAs8yEqWEqhSZo9nYhbm57jx7qHXtgRmv/nmeQIjjMcwf6Dl+y5UZcGWgWx435TAYBURONaJIuCjWg==",
"version": "20.5.0",
"resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.5.0.tgz",
"integrity": "sha512-t3Ni88rFw1XMa4nZHgOKJ8fIAT9M2j5TnKyTqJzsxea7FUetlNdYFus9dz+MhIRZmc16P0PPyEfh6X2d/qw8SA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@commitlint/types": "^20.4.3",
"@commitlint/types": "^20.5.0",
"conventional-changelog-conventionalcommits": "^9.2.0"
},
"engines": {
@@ -401,9 +408,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz",
"integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz",
"integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==",
"cpu": [
"ppc64"
],
@@ -418,9 +425,9 @@
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz",
"integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz",
"integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==",
"cpu": [
"arm"
],
@@ -435,9 +442,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz",
"integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz",
"integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==",
"cpu": [
"arm64"
],
@@ -452,9 +459,9 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz",
"integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz",
"integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==",
"cpu": [
"x64"
],
@@ -469,9 +476,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz",
"integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz",
"integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==",
"cpu": [
"arm64"
],
@@ -486,9 +493,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz",
"integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz",
"integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==",
"cpu": [
"x64"
],
@@ -503,9 +510,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz",
"integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz",
"integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==",
"cpu": [
"arm64"
],
@@ -520,9 +527,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz",
"integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz",
"integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==",
"cpu": [
"x64"
],
@@ -537,9 +544,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz",
"integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz",
"integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==",
"cpu": [
"arm"
],
@@ -554,9 +561,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz",
"integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz",
"integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==",
"cpu": [
"arm64"
],
@@ -571,9 +578,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz",
"integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz",
"integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==",
"cpu": [
"ia32"
],
@@ -588,9 +595,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz",
"integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz",
"integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==",
"cpu": [
"loong64"
],
@@ -605,9 +612,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz",
"integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz",
"integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==",
"cpu": [
"mips64el"
],
@@ -622,9 +629,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz",
"integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz",
"integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==",
"cpu": [
"ppc64"
],
@@ -639,9 +646,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz",
"integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz",
"integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==",
"cpu": [
"riscv64"
],
@@ -656,9 +663,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz",
"integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz",
"integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==",
"cpu": [
"s390x"
],
@@ -673,9 +680,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz",
"integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz",
"integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==",
"cpu": [
"x64"
],
@@ -690,9 +697,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz",
"integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz",
"integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==",
"cpu": [
"arm64"
],
@@ -707,9 +714,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz",
"integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz",
"integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==",
"cpu": [
"x64"
],
@@ -724,9 +731,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz",
"integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz",
"integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==",
"cpu": [
"arm64"
],
@@ -741,9 +748,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz",
"integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz",
"integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==",
"cpu": [
"x64"
],
@@ -758,9 +765,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz",
"integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz",
"integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==",
"cpu": [
"arm64"
],
@@ -775,9 +782,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz",
"integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz",
"integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==",
"cpu": [
"x64"
],
@@ -792,9 +799,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz",
"integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz",
"integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==",
"cpu": [
"arm64"
],
@@ -809,9 +816,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz",
"integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz",
"integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==",
"cpu": [
"ia32"
],
@@ -826,9 +833,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz",
"integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz",
"integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==",
"cpu": [
"x64"
],
@@ -1048,9 +1055,9 @@
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz",
"integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==",
"version": "2.10.15",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.15.tgz",
"integrity": "sha512-1nfKCq9wuAZFTkA2ey/3OXXx7GzFjLdkTiFVNwlJ9WqdI706CZRIhEqjuwanjMIja+84jDLa9rcyZDPDiVkASQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -1242,13 +1249,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/colord": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
"integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
"dev": true,
"license": "MIT"
},
"node_modules/commander": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
@@ -1436,13 +1436,13 @@
}
},
"node_modules/cssnano": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.3.tgz",
"integrity": "sha512-mLFHQAzyapMVFLiJIn7Ef4C2UCEvtlTlbyILR6B5ZsUAV3D/Pa761R5uC1YPhyBkRd3eqaDm2ncaNrD7R4mTRg==",
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.4.tgz",
"integrity": "sha512-T9PNS7y+5Nc9Qmu9mRONqfxG1RVY7Vuvky0XN6MZ+9hqplesTEwnj9r0ROtVuSwUVfaDhVlavuzWIVLUgm4hkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"cssnano-preset-default": "^7.0.11",
"cssnano-preset-default": "^7.0.12",
"lilconfig": "^3.1.3"
},
"engines": {
@@ -1457,15 +1457,15 @@
}
},
"node_modules/cssnano-preset-advanced": {
"version": "7.0.11",
"resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-7.0.11.tgz",
"integrity": "sha512-k9Dz/8TBOmLojoMZ+2xwrGjscU1XwYVDVB9T1AmvZcwiWz4ibWm8/y+/SN5jhYcpMPTeDe7FhI2uEYlNq1iDGg==",
"version": "7.0.12",
"resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-7.0.12.tgz",
"integrity": "sha512-S+UCfEMBCaYqNmjY+yCTNh4ur+B83z5qpwkzUMER6kVpdQ5CBUxIkALZGhp2KPP3M4VefRCIBMqJ6Z0PFMwvEA==",
"dev": true,
"license": "MIT",
"dependencies": {
"autoprefixer": "^10.4.27",
"browserslist": "^4.28.1",
"cssnano-preset-default": "^7.0.11",
"cssnano-preset-default": "^7.0.12",
"postcss-discard-unused": "^7.0.5",
"postcss-merge-idents": "^7.0.1",
"postcss-reduce-idents": "^7.0.1",
@@ -1479,9 +1479,9 @@
}
},
"node_modules/cssnano-preset-default": {
"version": "7.0.11",
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.11.tgz",
"integrity": "sha512-waWlAMuCakP7//UCY+JPrQS1z0OSLeOXk2sKWJximKWGupVxre50bzPlvpbUwZIDylhf/ptf0Pk+Yf7C+hoa3g==",
"version": "7.0.12",
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.12.tgz",
"integrity": "sha512-B3Eoouzw/sl2zANI0AL9KbacummJTCww+fkHaDBMZad/xuVx8bUduPLly6hKVQAlrmvYkS1jB1CVQEKm3gn0AA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1489,7 +1489,7 @@
"css-declaration-sorter": "^7.2.0",
"cssnano-utils": "^5.0.1",
"postcss-calc": "^10.1.1",
"postcss-colormin": "^7.0.6",
"postcss-colormin": "^7.0.7",
"postcss-convert-values": "^7.0.9",
"postcss-discard-comments": "^7.0.6",
"postcss-discard-duplicates": "^7.0.2",
@@ -1498,7 +1498,7 @@
"postcss-merge-longhand": "^7.0.5",
"postcss-merge-rules": "^7.0.8",
"postcss-minify-font-values": "^7.0.1",
"postcss-minify-gradients": "^7.0.1",
"postcss-minify-gradients": "^7.0.2",
"postcss-minify-params": "^7.0.6",
"postcss-minify-selectors": "^7.0.6",
"postcss-normalize-charset": "^7.0.1",
@@ -1709,9 +1709,9 @@
}
},
"node_modules/esbuild": {
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz",
"integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
"integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -1722,32 +1722,32 @@
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.27.3",
"@esbuild/android-arm": "0.27.3",
"@esbuild/android-arm64": "0.27.3",
"@esbuild/android-x64": "0.27.3",
"@esbuild/darwin-arm64": "0.27.3",
"@esbuild/darwin-x64": "0.27.3",
"@esbuild/freebsd-arm64": "0.27.3",
"@esbuild/freebsd-x64": "0.27.3",
"@esbuild/linux-arm": "0.27.3",
"@esbuild/linux-arm64": "0.27.3",
"@esbuild/linux-ia32": "0.27.3",
"@esbuild/linux-loong64": "0.27.3",
"@esbuild/linux-mips64el": "0.27.3",
"@esbuild/linux-ppc64": "0.27.3",
"@esbuild/linux-riscv64": "0.27.3",
"@esbuild/linux-s390x": "0.27.3",
"@esbuild/linux-x64": "0.27.3",
"@esbuild/netbsd-arm64": "0.27.3",
"@esbuild/netbsd-x64": "0.27.3",
"@esbuild/openbsd-arm64": "0.27.3",
"@esbuild/openbsd-x64": "0.27.3",
"@esbuild/openharmony-arm64": "0.27.3",
"@esbuild/sunos-x64": "0.27.3",
"@esbuild/win32-arm64": "0.27.3",
"@esbuild/win32-ia32": "0.27.3",
"@esbuild/win32-x64": "0.27.3"
"@esbuild/aix-ppc64": "0.28.0",
"@esbuild/android-arm": "0.28.0",
"@esbuild/android-arm64": "0.28.0",
"@esbuild/android-x64": "0.28.0",
"@esbuild/darwin-arm64": "0.28.0",
"@esbuild/darwin-x64": "0.28.0",
"@esbuild/freebsd-arm64": "0.28.0",
"@esbuild/freebsd-x64": "0.28.0",
"@esbuild/linux-arm": "0.28.0",
"@esbuild/linux-arm64": "0.28.0",
"@esbuild/linux-ia32": "0.28.0",
"@esbuild/linux-loong64": "0.28.0",
"@esbuild/linux-mips64el": "0.28.0",
"@esbuild/linux-ppc64": "0.28.0",
"@esbuild/linux-riscv64": "0.28.0",
"@esbuild/linux-s390x": "0.28.0",
"@esbuild/linux-x64": "0.28.0",
"@esbuild/netbsd-arm64": "0.28.0",
"@esbuild/netbsd-x64": "0.28.0",
"@esbuild/openbsd-arm64": "0.28.0",
"@esbuild/openbsd-x64": "0.28.0",
"@esbuild/openharmony-arm64": "0.28.0",
"@esbuild/sunos-x64": "0.28.0",
"@esbuild/win32-arm64": "0.28.0",
"@esbuild/win32-ia32": "0.28.0",
"@esbuild/win32-x64": "0.28.0"
}
},
"node_modules/escalade": {
@@ -2554,15 +2554,15 @@
}
},
"node_modules/postcss-colormin": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.6.tgz",
"integrity": "sha512-oXM2mdx6IBTRm39797QguYzVEWzbdlFiMNfq88fCCN1Wepw3CYmJ/1/Ifa/KjWo+j5ZURDl2NTldLJIw51IeNQ==",
"version": "7.0.7",
"resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.7.tgz",
"integrity": "sha512-sBQ628lSj3VQpDquQel8Pen5mmjFPsO4pH9lDLaHB1AVkMRHtkl0pRB5DCWznc9upWsxint/kV+AveSj7W1tew==",
"dev": true,
"license": "MIT",
"dependencies": {
"@colordx/core": "^5.0.0",
"browserslist": "^4.28.1",
"caniuse-api": "^3.0.0",
"colord": "^2.9.3",
"postcss-value-parser": "^4.2.0"
},
"engines": {
@@ -2808,13 +2808,13 @@
}
},
"node_modules/postcss-minify-gradients": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.1.tgz",
"integrity": "sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==",
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.2.tgz",
"integrity": "sha512-fVY3AB8Um7SJR5usHqTY2Ngf9qh8IRN+FFzrBP0ONJy6yYXsP7xyjK2BvSAIrpgs1cST+H91V0TXi3diHLYJtw==",
"dev": true,
"license": "MIT",
"dependencies": {
"colord": "^2.9.3",
"@colordx/core": "^5.0.0",
"cssnano-utils": "^5.0.1",
"postcss-value-parser": "^4.2.0"
},
@@ -3182,9 +3182,9 @@
}
},
"node_modules/preact": {
"version": "10.28.4",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.28.4.tgz",
"integrity": "sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ==",
"version": "10.29.1",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.29.1.tgz",
"integrity": "sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==",
"license": "MIT",
"funding": {
"type": "opencollective",
+7 -7
View File
@@ -20,12 +20,12 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@commitlint/cli": "^20.4.3",
"@commitlint/config-conventional": "^20.4.3",
"baseline-browser-mapping": "^2.10.0",
"cssnano": "^7.1.3",
"cssnano-preset-advanced": "^7.0.11",
"esbuild": "^0.27.3",
"@commitlint/cli": "^20.5.0",
"@commitlint/config-conventional": "^20.5.0",
"baseline-browser-mapping": "^2.10.15",
"cssnano": "^7.1.4",
"cssnano-preset-advanced": "^7.0.12",
"esbuild": "^0.28.0",
"husky": "^9.1.7",
"playwright": "^1.52.0",
"postcss-cli": "^11.0.1",
@@ -36,7 +36,7 @@
},
"dependencies": {
"@aws-crypto/sha256-js": "^5.2.0",
"preact": "^10.28.4"
"preact": "^10.29.1"
},
"commitlint": {
"extends": [