- 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.
The build stage of the Dockerfile runs `COPY . .`, so anything left in the
checkout root is sent to the builder and copied into the build stage. Exclude
the local secrets and backups that the install and backup scripts create
there: .env, config.json, jwt.key and backups/. keys/ was already excluded.
The Docker Compose (manual) section of the README still told users to build
the single binary before `docker compose up -d --build`. Since the
multi-stage Dockerfile builds the frontend and the Go binary itself, that
step is no longer needed; remove it.
- README: ARTEX_TRUSTED_PROXIES for nginx and ARTEX on the host
(127.0.0.1) and for nginx on the host with ARTEX in Docker (the bridge
gateway, found with docker network inspect).
- CI shell job: run shellcheck on reset-password.sh too.
- 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.
The update source is hard-coded to a repository that no longer exists and the release checksums are unsigned. Removes the selfupdate package and the /api/update/* endpoints, the top-bar check that queried GitHub on every page load, the Version & Updates card, and the exit-75 swap protocol in the start scripts.
scripts/backup.sh dumps the Postgres database through the postgres compose
service (no host psql needed) into timestamped gzip files under backups/,
keeping the newest N (default 14). --with-data additionally tars the
bind-mounted data directory and fails loudly when files written by the
container are unreadable instead of shipping a partial archive. README gains
a Backups section with the restore one-liner and a cron example.
Closes#40
The original ARTEX repository no longer exists upstream, so both clone
URLs and both Releases links pointed at 404s: they now point at this
fork, which is the maintained source. The live demo lines and the
WeChat community group section (with its QR code screenshot) belonged
to the original author's channels and are removed. The References,
ScopeSentry, norma and AegisHook links stay (all alive, all
meaningful).
The repo is public now, so the header no longer says it is kept
private. The usage terms still described a learning-only toy, which
contradicted what the tool is; they now require explicit
authorization (own systems, labs, or bounty program scope) and drop
the mainland-China-specific law list for a general jurisdiction line.
All em dashes are replaced with standard punctuation.
Closes#33. The MITM proxy only sees the agent's own actions, so
anything behind a human gate (signup captcha, email OTP, 2FA, SSO)
left the authenticated surface dark. The operator's browser becomes a
capture source instead:
- traffic: exported RecordExternal storing an externally captured
exchange through the same spill/blob/FTS path as proxy traffic
(insert logic shared with record()); rejects unparsable URLs and
empty methods
- server: POST /api/traffic/ingest inside the authenticated API group,
batch capped at 50 entries, bodies truncated at 256 KiB, per-entry
ingested/failed counts
- extension/: Manifest V3 Chrome/Edge extension driving the
chrome.debugger Network domain on the chosen tab, batching text
exchanges to the ingest endpoint with the operator's URL + JWT in
chrome.storage.local; binary bodies skipped; flush on batch/stop
- tests for both layers, README section
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