- resetSettledRun clears settling and the budget ledger; a done/failed task
revived to running now plans and claims again (was gated by the old wrap-up).
resetTimeoutRevival calls it. Test: TestResetSettledRunRestartsBudget.
- docker-compose.yml passes the four ARTEX_*_BUDGET_* variables through.
- .env.example and README document the variables, the wrap-up, the in-memory
ledger and the practical floor.
- llmrec: the usage sink runs even without a PostgreSQL recorder; comment fixed.
- BudgetWrapupBlocks allows update_finding_report.
ARTEX_NOISE_PROFILE = off | quiet | balanced | aggressive drives one shared
governor used by WebFetch, the http custom tools and the enrich probe: token
bucket, bounded jitter and concurrency per host, a global cap, backoff on
429/503 honouring Retry-After with bounded retries, per-task coalescing and
a short cache of identical GETs (never POST/PUT/PATCH/DELETE), and a
per-host noise log line each minute. Off (the default) is a strict
passthrough.
Removes the fixed artex-enrich/1.0 User-Agent; ARTEX_TARGET_USER_AGENT sets
one under a profile (empty = unchanged).
ARTEX_UNTRUSTED_BOUNDARY unset or empty now enables the boundary.
0, false, off and no (case-insensitive, trimmed) disable it; any other
value keeps it on. Docs state the default, the opt-out and the measured
cost (about 154 bytes per tool result plus one system note).
ARTEX_UPDATE_CHECK=1 lets the backend check the public GitHub releases API
for the latest tag at most once per 24 h (in-memory cache; failures are not
retried in the window) and report it in GET /api/health when it is newer
than the build version. The web UI shows a dismissible strip linking to the
Releases page. Unset (the default), no update request is made.
- ARTEX_TRUSTED_PROXIES (comma-separated CIDRs, empty by default). When
the TCP peer is listed, the login limit reads X-Forwarded-For from the
right and keys on the first hop that is not a trusted proxy; otherwise
the header is ignored. Without it every client behind a reverse proxy
shares one bucket and an attacker can block the admin. Passed through
by docker-compose.yml and listed in .env.example.
- README: nginx example sends X-Forwarded-For; document the variable;
the binary's default listen address is 127.0.0.1:8787.
- reset-password.sh refuses passwords under 12 characters, counted in
characters like the server.
The server wrote jwt.key to the executable's directory, /app in the
image, so it lived in the container's writable layer and every container
rebuild generated a new key and signed all users out.
- ARTEX_JWT_KEY_DIR selects the key directory (default: config.BaseDir(),
unchanged for non-Docker installs). docker-compose.yml sets it to
/app/keys and bind-mounts ./keys there; the Dockerfile declares the
volume. The key stays out of data/, which the file manager browses.
- loadOrCreateJWTKey creates the directory (0700). When keyDir/jwt.key is
missing it migrates dataDir/jwt.key, then BaseDir()/jwt.key (mode 0600,
old file removed), otherwise generates a new key. An existing key is
never overwritten; a short one is now a startup error.
- .gitignore and .dockerignore exclude keys/.
- README and CHANGELOG updated; the 0.5.0 known issue is removed.
Publishing 127.0.0.1:8787 removed the only working access path for installs
reached through a host or WSL IP, without an obvious way back. Keep loopback as
the default and let ARTEX_BIND_ADDR override it (0.0.0.0 restores the old
behaviour; the setup token still protects the first-run claim).
POST /api/auth/init accepted any caller while auth.password_hash was empty,
so whoever reached port 8787 first could set the admin password and take the
instance. When no password is set at startup, the server now generates a
random one-time setup token and writes it to the server log. authInit
compares it in constant time, rejects a missing or wrong token with 403, and
clears it once the password is stored.
The setup page has a field for the token and api.initPassword sends it.
docker-compose publishes 8787 on 127.0.0.1 only, like 8788. README says where
to find the token.
docker-compose.yml referenced autumn27/artex:latest. That repository is gone
(404), but the Docker Hub account is alive, so whoever holds that name can
publish the tag and every compose pull would run their image. A local review
of the published artifacts found the same class of risk still present on the
default install path after #125 removed the in-app updater.
Build from the checkout instead, and make update.sh stop when git pull cannot
fast-forward: it used to warn, rebuild the old tree and print 'Build complete',
which is what every clone made before the 2026-10-23 history rewrite now hits.
Comments, doc comments, UI labels, log and error messages, LLM prompt
strings, markdown docs, test data and assertions. Identifiers, enum
keys, routes, placeholders and code structure are unchanged.
Notes:
- docs/漏洞流量证据.md renamed to docs/vulnerability-traffic-evidence.md
- tests that exercised CJK specific handling (GBK zip names, Chinese
full text search) now use ASCII equivalents; go build passes and the
test suite matches the pre translation baseline (remaining failures
need a PostgreSQL DSN and fail identically on the original)
- frontend mention syntax now uses English kinds (finding, asset, ...)
matching the backend, chat mentions tests pass