Compare commits

..

3 Commits

Author SHA1 Message Date
Xe Iaso
c67b4c16a6 fix(data/docker-client): add containerd
Signed-off-by: Xe Iaso <me@xeiaso.net>
2025-11-08 12:44:18 -05:00
Xe Iaso
039da9aa1c Update metadata
check-spelling run (pull_request) for Xe/more-docker-client-programs

Signed-off-by: check-spelling-bot <check-spelling-bot@users.noreply.github.com>
on-behalf-of: @check-spelling <check-spelling-bot@check-spelling.dev>
2025-11-08 12:43:25 -05:00
Xe Iaso
81ead403c2 fix(data/docker-client): allow some more OCI clients through
Signed-off-by: Xe Iaso <me@xeiaso.net>
2025-11-08 12:42:03 -05:00
27 changed files with 119 additions and 272 deletions

View File

@@ -1,12 +1,12 @@
services:
playwright:
image: mcr.microsoft.com/playwright:v1.56.0-noble
image: mcr.microsoft.com/playwright:v1.52.0-noble
init: true
network_mode: service:workspace
command:
- /bin/sh
- -c
- npx -y playwright@1.56.0 run-server --port 9001 --host 0.0.0.0
- npx -y playwright@1.52.0 run-server --port 9001 --host 0.0.0.0
valkey:
image: valkey/valkey:8

View File

@@ -8,4 +8,3 @@ msgbox
xeact
ABee
tencent
maintnotifications

View File

@@ -22,11 +22,11 @@ jobs:
sudo apt-get update
sudo apt-get install -y build-essential
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: latest
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: stable

View File

@@ -26,11 +26,11 @@ jobs:
sudo apt-get update
sudo apt-get install -y build-essential
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: latest
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: stable
@@ -38,7 +38,7 @@ jobs:
- name: Docker meta
id: meta
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
with:
images: ghcr.io/${{ github.repository }}

View File

@@ -36,11 +36,11 @@ jobs:
run: |
echo "IMAGE=ghcr.io/${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: latest
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: stable
@@ -55,7 +55,7 @@ jobs:
- name: Docker meta
id: meta
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
with:
images: ${{ env.IMAGE }}

View File

@@ -33,7 +33,7 @@ jobs:
- name: Docker meta
id: meta
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
with:
images: ghcr.io/techarohq/anubis/docs
tags: |

View File

@@ -22,7 +22,7 @@ jobs:
- name: Docker meta
id: meta
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
with:
images: ghcr.io/techarohq/anubis/docs
tags: |

View File

@@ -24,11 +24,11 @@ jobs:
sudo apt-get update
sudo apt-get install -y build-essential
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: latest
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: stable
@@ -38,7 +38,7 @@ jobs:
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-1.56.0
key: ${{ runner.os }}-playwright-${{ hashFiles('**/go.sum') }}
- name: install node deps
run: |
@@ -46,8 +46,8 @@ jobs:
- name: install playwright browsers
run: |
npx playwright@1.56.0 install --with-deps
npx playwright@1.56.0 run-server --port 9001 &
npx --no-install playwright@1.52.0 install --with-deps
npx --no-install playwright@1.52.0 run-server --port 9001 &
- name: Build
run: npm run build

View File

@@ -25,11 +25,11 @@ jobs:
sudo apt-get update
sudo apt-get install -y build-essential
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: latest
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: stable

View File

@@ -26,11 +26,11 @@ jobs:
sudo apt-get update
sudo apt-get install -y build-essential
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: latest
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: stable

View File

@@ -51,10 +51,3 @@
all:
- path.startsWith("/v2/")
- userAgent.contains("containerd/")
- name: allow-renovate
action: ALLOW
expression:
all:
- path.startsWith("/v2/")
- userAgent.contains("Renovate/")

View File

@@ -3,6 +3,6 @@ package data
import "embed"
var (
//go:embed botPolicies.yaml all:apps all:bots all:clients all:common all:crawlers all:meta all:services
//go:embed botPolicies.yaml all:apps all:bots all:clients all:common all:crawlers all:meta
BotPolicies embed.FS
)

View File

@@ -1,38 +0,0 @@
package data
import (
"path/filepath"
"strings"
"testing"
)
// TestBotPoliciesEmbed ensures all YAML files in the directory tree
// are accessible in the embedded BotPolicies filesystem.
func TestBotPoliciesEmbed(t *testing.T) {
yamlFiles, err := filepath.Glob("./**/*.yaml")
if err != nil {
t.Fatalf("Failed to glob YAML files: %v", err)
}
if len(yamlFiles) == 0 {
t.Fatal("No YAML files found in directory tree")
}
t.Logf("Found %d YAML files to verify", len(yamlFiles))
for _, filePath := range yamlFiles {
embeddedPath := strings.TrimPrefix(filePath, "./")
t.Run(embeddedPath, func(t *testing.T) {
content, err := BotPolicies.ReadFile(embeddedPath)
if err != nil {
t.Errorf("Failed to read %s from embedded filesystem: %v", embeddedPath, err)
return
}
if len(content) == 0 {
t.Errorf("File %s exists in embedded filesystem but is empty", embeddedPath)
}
})
}
}

View File

@@ -1,4 +1,4 @@
FROM docker.io/library/node:lts AS build
FROM docker.io/library/node AS build
WORKDIR /app
COPY . .

View File

@@ -13,14 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- This changes the project to: -->
- Expose WEIGHT rule matches as Prometheus metrics.
- Allow more OCI registry clients [based on feedback](https://github.com/TecharoHQ/anubis/pull/1253#issuecomment-3506744184).
- Expose services directory in the embedded `(data)` filesystem.
- Add Ukrainian locale ([#1044](https://github.com/TecharoHQ/anubis/pull/1044)).
- Allow Renovate as an OCI registry client.
- Properly handle 4in6 addresses so that IP matching works with those addresses.
- Add support to simple Valkey/Redis cluster mode
- Bump the Playwright dev dependency to 1.56.0
## v1.23.1: Lyse Hext - Echo 1

View File

@@ -99,7 +99,7 @@ const (
actionChallenge action = "CHALLENGE"
placeholderIP = "fd11:5ee:bad:c0de::"
playwrightVersion = "1.56.0"
playwrightVersion = "1.52.0"
)
type action string

View File

@@ -576,7 +576,6 @@ func (s *Server) check(r *http.Request, lg *slog.Logger) (policy.CheckResult, *p
return cr("bot/"+b.Name, b.Action, weight), &b, nil
case config.RuleWeigh:
lg.Debug("adjusting weight", "name", b.Name, "delta", b.Weight.Adjust)
policy.Applications.WithLabelValues("bot/"+b.Name, "WEIGH").Add(1)
weight += b.Weight.Adjust
}
}

View File

@@ -18,7 +18,6 @@
"pt-BR",
"ru",
"tr",
"uk",
"vi",
"zh-CN",
"zh-TW",

View File

@@ -1,66 +0,0 @@
{
"loading": "Завантаження...",
"why_am_i_seeing": "Чому я це бачу?",
"protected_by": "Захищено засобами",
"protected_from": "за авторством",
"made_with": "Зроблено з ❤️ у 🇨🇦",
"mascot_design": "Дизайн персонажа від",
"ai_companies_explanation": "Ви це бачите, оскільки адміністрація сайту налаштувала Anubis, щоб захистити сервер від тиску ШІ-компаній, які агресивно сканують вебсайти. Їхня діяльність спричиняє перебої в роботі вебсайтів, що робить матеріали недоступними для всіх.",
"anubis_compromise": "Anubis — це компроміс. Anubis втілює схему доказу виконаної роботи подібно до Hashcash — засобу боротьби зі спамом. По ідеї, додаткове навантаження не обтяжує справжню людину, котра робить небагато запитів, а от масове сканування таким чином стає суттєво дорожчим.",
"hack_purpose": "Це тимчасове рішення, котре дозволяє приділити більше часу розпізнанню й виокремленню автоматизованих браузерів (наприклад, за тим, як вони промальовують шрифти), щоб сторінку перевірки доказу виконаної роботи не доводилося показувати ймовірно справжнім користувачам.",
"simplified_explanation": "Це засіб боротьби з ботами й зловмисними запитами, подібний до капчі. Проте замість того, щоб просити вас щось зробити, він пропонує вашому браузеру розв'язати обчислювальне завдання. Ця концепція називається <a href=\"https://en.wikipedia.org/wiki/Proof_of_work\">доказом виконаної роботи</a>. Завдання обчислюється кілька секунд, після чого вам надається доступ до сайту. Дякуємо за розуміння й терплячість.",
"jshelter_note": "Зауважте, Anubis потребує сучасного JavaScript-функціоналу, котрий може бути недоступним при використанні розширень на зразок JShelter. Будь ласка, вимкніть JShelter чи інші подібні розширення для цього домену.",
"version_info": "Цей вебсайт застосовує Anubis версії",
"try_again": "Повторіть спробу",
"go_home": "Перейдіть на головну сторінку",
"contact_webmaster": "або, якщо ви певні в помилковості блокування, сконтактуйте з адміністрацією за адресою",
"connection_security": "Зачекайте хвилинку, поки ми перевіримо безпеку вашого з'єднання.",
"javascript_required": "На жаль, вам потрібно ввімкнути JavaScript, щоб пройти цю перевірку. Це необхідно, оскільки ШІ-компанії нехтують суспільним договором, завдяки якому можливо утримувати вебсайти. Робота над рішенням без використання JS триває.",
"benchmark_requires_js": "Щоб запустити тестування продуктивності, ввімкніть JavaScript.",
"difficulty": "Складність:",
"algorithm": "Алгоритм:",
"compare": "Порівняти:",
"time": "Час",
"iters": "Ітерації",
"time_a": "Час A",
"iters_a": "Ітерації A",
"time_b": "Час B",
"iters_b": "Ітерації B",
"static_check_endpoint": "Це просто сторінка перевірки для вашого зворотного проксі.",
"authorization_required": "Необхідно авторизуватися",
"cookies_disabled": "У вашому браузері вимкнено кукі. Anubis використовує кукі, щоб упевнитись, що ви дійсно людина. Це законний інтерес. Будь ласка, ввімкніть кукі для цього домену",
"access_denied": "Доступ заборонено: код помилки",
"dronebl_entry": "DroneBL містить пункт",
"see_dronebl_lookup": "див.",
"internal_server_error": "Внутрішня помилка сервера: адміністрація хибно налаштувала Anubis. Будь ласка, сконтактуйте з адміністрацією й попросіть глянути логи довкола",
"invalid_redirect": "Хибне переспрямування",
"redirect_not_parseable": "Не вдається розпізнати URL-адресу переспрямування",
"redirect_domain_not_allowed": "Заборонений домен переспрямування",
"missing_required_forwarded_headers": "Бракує обов'язкових заголовків X-Forwarded-*",
"failed_to_sign_jwt": "не вдається підписати JWT",
"invalid_invocation": "Хибний виклик MakeChallenge",
"client_error_browser": "Помилка клієнта: переконайтесь, що використовуєте браузер актуальної версії, й повторіть спробу.",
"oh_noes": "Йой!",
"benchmarking_anubis": "Тестування продуктивності Anubis!",
"you_are_not_a_bot": "Ви не бот!",
"making_sure_not_bot": "Перевірка, чи ви не бот!",
"celphase": "CELPHASE",
"js_web_crypto_error": "Ваш браузер не надає web.crypto. Ви певні, що дивитесь це через захищений контекст?",
"js_web_workers_error": "Ваш браузер не підтримує Web Workers (Anubis використовує їх, щоб ваш браузер не зависав на час перевірки). Можливо, у вас встановлено розширення на зразок JShelter?",
"js_cookies_error": "Ваш браузер не зберігає кукі. Anubis записує підписаний токен до кукі, щоб занотувати, що клієнт пройшов перевірку. Будь ласка, ввімкніть збереження кукі для цього домену. Назви кукі, які записує Anubis, можуть змінюватися без попередження. Назви й значення кукі не є частиною публічного API.",
"js_context_not_secure": "Ваш контекст незахищений!",
"js_context_not_secure_msg": "Спробуйте з'єднатися через HTTPS або попросіть адміністрацію налаштувати HTTPS. Докладніше — в <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>.",
"js_calculating": "Обчислення...",
"js_missing_feature": "Бракує функціоналу",
"js_challenge_error": "Помилка перевірки!",
"js_challenge_error_msg": "Не вдалося визначити алгоритм перевірки. Спробуйте оновити сторінку.",
"js_calculating_difficulty": "Обчислення...<br/>Складність:",
"js_speed": "Швидкість:",
"js_verification_longer": "Перевірка триває довше, ніж очікувалося. Будь ласка, не оновлюйте сторінку.",
"js_success": "Успіх!",
"js_done_took": "Готово! Знадобилося",
"js_iterations": "ітерацій",
"js_finished_reading": "Читання завершено, продовжити →",
"js_calculation_error": "Помилка обчислення!",
"js_calculation_error_msg": "Не вдалося обчислити перевірку:"
}

View File

@@ -27,7 +27,6 @@ func TestLocalizationService(t *testing.T) {
"pt-BR": "Carregando...",
"tr": "Yükleniyor...",
"ru": "Загрузка...",
"uk": "Завантаження...",
"vi": "Đang nạp...",
"zh-CN": "加载中...",
"zh-TW": "載入中...",

View File

@@ -51,11 +51,6 @@ func (rac *RemoteAddrChecker) Check(r *http.Request) (bool, error) {
return false, fmt.Errorf("%w: %s is not an IP address: %w", ErrMisconfiguration, host, err)
}
// Convert IPv4-mapped IPv6 addresses to IPv4
if addr.Is6() && addr.Is4In6() {
addr = addr.Unmap()
}
return rac.prefixTable.Contains(addr), nil
}

View File

@@ -21,20 +21,6 @@ func TestRemoteAddrChecker(t *testing.T) {
ok: true,
err: nil,
},
{
name: "match_ipv4_in_ipv6",
cidrs: []string{"0.0.0.0/0"},
ip: "::ffff:1.1.1.1",
ok: true,
err: nil,
},
{
name: "match_ipv4_in_ipv6_hex",
cidrs: []string{"0.0.0.0/0"},
ip: "::ffff:101:101",
ok: true,
err: nil,
},
{
name: "match_ipv6",
cidrs: []string{"::/0"},

View File

@@ -5,98 +5,80 @@ import (
"encoding/json"
"errors"
"fmt"
"time"
"github.com/TecharoHQ/anubis/lib/store"
valkey "github.com/redis/go-redis/v9"
"github.com/redis/go-redis/v9/maintnotifications"
)
var (
ErrNoURL = errors.New("valkey.Config: no URL defined")
ErrBadURL = errors.New("valkey.Config: URL is invalid")
)
func init() {
store.Register("valkey", Factory{})
}
// Errors kept as-is so other code/tests still pass.
var (
ErrNoURL = errors.New("valkey.Config: no URL defined")
ErrBadURL = errors.New("valkey.Config: URL is invalid")
)
type Factory struct{}
// Config is what Anubis unmarshals from the "parameters" JSON.
type Config struct {
URL string `json:"url"`
Cluster bool `json:"cluster,omitempty"`
}
func (Factory) Build(ctx context.Context, data json.RawMessage) (store.Interface, error) {
var config Config
func (c Config) Valid() error {
if c.URL == "" {
return ErrNoURL
if err := json.Unmarshal([]byte(data), &config); err != nil {
return nil, fmt.Errorf("%w: %w", store.ErrBadConfig, err)
}
// Just validate that it's a valid Redis URL.
if _, err := valkey.ParseURL(c.URL); err != nil {
return fmt.Errorf("%w: %v", ErrBadURL, err)
if err := config.Valid(); err != nil {
return nil, fmt.Errorf("%w: %w", store.ErrBadConfig, err)
}
opts, err := valkey.ParseURL(config.URL)
if err != nil {
return nil, fmt.Errorf("%w: %w", store.ErrBadConfig, err)
}
rdb := valkey.NewClient(opts)
if _, err := rdb.Ping(ctx).Result(); err != nil {
return nil, fmt.Errorf("can't ping valkey instance: %w", err)
}
return &Store{
rdb: rdb,
}, nil
}
func (Factory) Valid(data json.RawMessage) error {
var config Config
if err := json.Unmarshal([]byte(data), &config); err != nil {
return fmt.Errorf("%w: %w", store.ErrBadConfig, err)
}
if err := config.Valid(); err != nil {
return fmt.Errorf("%w: %w", store.ErrBadConfig, err)
}
return nil
}
// redisClient is satisfied by *valkey.Client and *valkey.ClusterClient.
type redisClient interface {
Get(ctx context.Context, key string) *valkey.StringCmd
Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *valkey.StatusCmd
Del(ctx context.Context, keys ...string) *valkey.IntCmd
Ping(ctx context.Context) *valkey.StatusCmd
type Config struct {
URL string `json:"url"`
}
type Factory struct{}
func (c Config) Valid() error {
var errs []error
func (Factory) Valid(data json.RawMessage) error {
var cfg Config
if err := json.Unmarshal(data, &cfg); err != nil {
return err
if c.URL == "" {
errs = append(errs, ErrNoURL)
}
return cfg.Valid()
}
func (Factory) Build(ctx context.Context, data json.RawMessage) (store.Interface, error) {
var cfg Config
if err := json.Unmarshal(data, &cfg); err != nil {
return nil, err
}
if err := cfg.Valid(); err != nil {
return nil, err
}
opts, err := valkey.ParseURL(cfg.URL)
if err != nil {
return nil, fmt.Errorf("valkey.Factory: %w", err)
}
var client redisClient
if cfg.Cluster {
// Cluster mode: use the parsed Addr as the seed node.
clusterOpts := &valkey.ClusterOptions{
Addrs: []string{opts.Addr},
// Explicitly disable maintenance notifications
// This prevents the client from sending CLIENT MAINT_NOTIFICATIONS ON
MaintNotificationsConfig: &maintnotifications.Config{
Mode: maintnotifications.ModeDisabled,
},
}
client = valkey.NewClusterClient(clusterOpts)
} else {
opts.MaintNotificationsConfig = &maintnotifications.Config{
Mode: maintnotifications.ModeDisabled,
}
client = valkey.NewClient(opts)
}
// Optional but nice: fail fast if the cluster/single node is unreachable.
if err := client.Ping(ctx).Err(); err != nil {
return nil, fmt.Errorf("valkey.Factory: ping failed: %w", err)
}
return &Store{client: client}, nil
if _, err := valkey.ParseURL(c.URL); err != nil {
errs = append(errs, ErrBadURL)
}
if len(errs) != 0 {
return fmt.Errorf("valkey.Config: invalid config: %w", errors.Join(errs...))
}
return nil
}

View File

@@ -2,46 +2,52 @@ package valkey
import (
"context"
"fmt"
"time"
"github.com/TecharoHQ/anubis/lib/store"
valkey "github.com/redis/go-redis/v9"
)
// Store implements store.Interface on top of Redis/Valkey.
type Store struct {
client redisClient
}
var _ store.Interface = (*Store)(nil)
func (s *Store) Get(ctx context.Context, key string) ([]byte, error) {
cmd := s.client.Get(ctx, key)
if err := cmd.Err(); err != nil {
if err == valkey.Nil {
return nil, store.ErrNotFound
}
return nil, err
}
return cmd.Bytes()
}
func (s *Store) Set(ctx context.Context, key string, value []byte, expiry time.Duration) error {
return s.client.Set(ctx, key, value, expiry).Err()
rdb *valkey.Client
}
func (s *Store) Delete(ctx context.Context, key string) error {
res := s.client.Del(ctx, key)
if err := res.Err(); err != nil {
return err
n, err := s.rdb.Del(ctx, key).Result()
if err != nil {
return fmt.Errorf("can't delete from valkey: %w", err)
}
if n, _ := res.Result(); n == 0 {
return store.ErrNotFound
switch n {
case 0:
return fmt.Errorf("%w: %d key(s) deleted", store.ErrNotFound, n)
default:
return nil
}
}
func (s *Store) Get(ctx context.Context, key string) ([]byte, error) {
result, err := s.rdb.Get(ctx, key).Result()
if err != nil {
if valkey.HasErrorPrefix(err, "redis: nil") {
return nil, fmt.Errorf("%w: %w", store.ErrNotFound, err)
}
return nil, fmt.Errorf("can't fetch from valkey: %w", err)
}
return []byte(result), nil
}
func (s *Store) Set(ctx context.Context, key string, value []byte, expiry time.Duration) error {
if _, err := s.rdb.Set(ctx, key, string(value), expiry).Result(); err != nil {
return fmt.Errorf("can't set %q in valkey: %w", key, err)
}
return nil
}
// IsPersistent tells Anubis this backend is “real” storage, not in-memory.
func (s *Store) IsPersistent() bool {
return true
}

16
package-lock.json generated
View File

@@ -16,7 +16,7 @@
"cssnano": "^7.1.2",
"cssnano-preset-advanced": "^7.0.10",
"esbuild": "^0.25.12",
"playwright": "^1.56.0",
"playwright": "^1.52.0",
"postcss-cli": "^11.0.1",
"postcss-import": "^16.1.1",
"postcss-import-url": "^7.2.0",
@@ -1603,13 +1603,13 @@
}
},
"node_modules/playwright": {
"version": "1.56.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
"integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz",
"integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.56.1"
"playwright-core": "1.52.0"
},
"bin": {
"playwright": "cli.js"
@@ -1622,9 +1622,9 @@
}
},
"node_modules/playwright-core": {
"version": "1.56.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz",
"integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz",
"integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==",
"dev": true,
"license": "Apache-2.0",
"bin": {

View File

@@ -21,7 +21,7 @@
"cssnano": "^7.1.2",
"cssnano-preset-advanced": "^7.0.10",
"esbuild": "^0.25.12",
"playwright": "^1.56.0",
"playwright": "^1.52.0",
"postcss-cli": "^11.0.1",
"postcss-import": "^16.1.1",
"postcss-import-url": "^7.2.0",
@@ -31,4 +31,4 @@
"@aws-crypto/sha256-js": "^5.2.0",
"preact": "^10.27.2"
}
}
}

0
run/openrc/anubis.initd Executable file → Normal file
View File