ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
detections / detections (push) Canceled after 0s
313 lines
19 KiB
Markdown
313 lines
19 KiB
Markdown
# Contributing
|
||
|
||
[한국어](CONTRIBUTING.md) · English
|
||
|
||
Thank you for your interest in the Korean edition of ARTEX (`artex-ko`). This document
|
||
gathers the scope, policies, and procedures you should know before you start contributing.
|
||
Before you send a contribution, please read [Authorized use and legal responsibility](#authorized-use-and-legal-responsibility)
|
||
and [Localization policy](#localization-policy) first.
|
||
|
||
- To report a bug or suggest a feature → use the [issue templates](https://github.com/jiwoochris/artex-ko/issues/new/choose).
|
||
- If you find a translation or localization error → use the "translation/localization error" issue template.
|
||
- If you find a security vulnerability → **do not open a public issue**; follow the procedure in [SECURITY.en.md](SECURITY.en.md).
|
||
- Everyone who takes part must follow the [Code of Conduct (CODE_OF_CONDUCT.en.md)](CODE_OF_CONDUCT.en.md).
|
||
|
||
---
|
||
|
||
## Authorized use and legal responsibility
|
||
|
||
ARTEX is an offensive-security tool in which an LLM multi-agent system performs penetration
|
||
testing **autonomously**. Contributors are bound by the same scope limits as users.
|
||
|
||
- When you verify code, run the tool only against **a target you own or have explicit written
|
||
authorization for**, or against a **locally isolated environment** (for example an
|
||
intentionally vulnerable target you own, such as OWASP Juice Shop or DVWA launched with Docker).
|
||
- We do not accept code that scans, probes, or exploits real, production, or remote systems
|
||
outside the authorized scope, nor changes that encourage such use.
|
||
- In the Republic of Korea, intruding into another party's information and communications
|
||
network without authorization, or causing a disruption to it, violates the Act on Promotion
|
||
of Information and Communications Network Utilization and Information Protection; and any
|
||
personal data collected or exposed falls under the Personal Information Protection Act. The
|
||
full notice is in the [README](README.en.md#️-read-first--authorized-use-and-legal-notice).
|
||
|
||
Legal responsibility for how the code or documentation you contribute is used rests with the
|
||
user who runs it. This repository is provided "AS IS."
|
||
|
||
---
|
||
|
||
## Localization policy
|
||
|
||
The reason this repository exists is to **preserve the original
|
||
[Autumn-27/ARTEX](https://github.com/Autumn-27/ARTEX)'s judgment performance exactly while
|
||
changing only the user-facing output to Korean**. Translation contributions that depart from
|
||
this policy can degrade performance, so we do not accept them.
|
||
|
||
- **Do not translate the agent's internal reasoning prompts (the behavior-instruction body).**
|
||
The behavior benchmarked in the original language (Chinese) must be preserved. This body
|
||
lives in `agent/promptcatalog.go` and the DB seed (`agent_prompts`). Translating it causes
|
||
drift in the agent's judgment.
|
||
- **Only user-facing output is forced into Korean.** This covers detection findings
|
||
(`report_finding`), fact summaries (`record_fact`), the final report, and chat responses.
|
||
The enforcement is a code-fixed tail called `langDirective()` in `agent/prompt.go`, appended
|
||
to the end of each role's system prompt. To change the output language, modify this function.
|
||
- **Commands, payloads, code, URLs, and log text are not translated.** They are the originals
|
||
needed for analysis, so they are left as is.
|
||
- **The original Chinese is preserved.** Documents keep the original in `README.zh.md` and UI
|
||
strings keep it in `web/messages/zh.json`, so that changes in the upstream repository are
|
||
easy to compare against. Korean translations are filled into `web/messages/ko.json`.
|
||
- When you translate a new UI string, do not hard-code it; add it as a key in the message files.
|
||
- **The output-language enforcement is a prompt nudge, not a hard cap.** `langDirective()`
|
||
**instructs** the model to output Korean; it does not force-lock the language. Korean fidelity
|
||
therefore varies with the model's capability, the role, and the context. Use a capable
|
||
(frontier-class) model when you verify localization changes. Cheap or small models can revert
|
||
reports and summaries to the original language (Chinese), so do not judge whether a translation
|
||
is applied correctly from a cheap model's output alone. The `max_tokens` pitfall when using
|
||
OpenAI-family models is covered in the
|
||
[README's "Model selection and output language" section](README.en.md#model-selection-and-output-language).
|
||
- **The procedure for keeping up with upstream changes is in the maintainer document.** When
|
||
the original ARTEX is updated, the runbook for distinguishing preserved assets from
|
||
translation targets, reflecting them, and checking translation symmetry and drift is in
|
||
[MAINTAINING.en.md](MAINTAINING.en.md).
|
||
|
||
---
|
||
|
||
## Development environment
|
||
|
||
This project consists of a **Go backend** (with the frontend embedded in a single binary) plus
|
||
a **Next.js frontend**.
|
||
|
||
The design intent of the main features is documented in the design docs under `docs/`. When you
|
||
work on the feature that links vulnerabilities to traffic evidence (the report agent's automatic
|
||
binding, `report_finding`'s `traffic_refs`, and so on), read the
|
||
[vulnerability multi-traffic-evidence design doc](docs/finding-traffic-evidence-en.md) first.
|
||
The original (Chinese) is preserved as `finding-traffic-evidence-zh.md` in the same folder.
|
||
|
||
### Required versions
|
||
|
||
- Go 1.26 or later (per `go.mod`)
|
||
- Node.js 22 or later (per the release workflow)
|
||
- Docker and Docker Compose (for local runs and verification)
|
||
|
||
### Backend (Go)
|
||
|
||
If Go is installed locally, run the following from the repository root.
|
||
|
||
```bash
|
||
go build ./...
|
||
go vet ./agent/
|
||
go test ./agent/
|
||
```
|
||
|
||
If you do not have Go locally, you can verify the same way with Docker. Keeping the module and
|
||
build caches in named volumes makes re-runs faster.
|
||
|
||
```bash
|
||
docker run --rm -v "$PWD":/src -w /src \
|
||
-v artexko-gomod:/go/pkg/mod -v artexko-gocache:/root/.cache/go-build \
|
||
golang:1.26 sh -c 'go build ./... && go vet ./agent/ && go test ./agent/'
|
||
```
|
||
|
||
#### DB integration tests (postgres required)
|
||
|
||
The `go test ./agent/` above **quietly skips the DB integration tests** that only run when
|
||
connected to PostgreSQL. Six packages — `agent`, `config`, `db`, `evidence`, `llmrec`,
|
||
`server` — contain tests that require a real database; if there is no `ARTEX_PG_DSN`
|
||
environment variable and no `database` entry in the config file, those tests are skipped with
|
||
`--- SKIP` and the package still ends in `ok`. As a result, if you fix one of these six
|
||
packages and verify without a DSN, **it can pass locally (ok) while the PR's `go-db` job
|
||
fails.**
|
||
|
||
To run these tests locally, bring up PostgreSQL and pass `ARTEX_PG_DSN`. The example below
|
||
launches the same `postgres:16-alpine` as CI on an isolated network, reusing the named volumes
|
||
from above.
|
||
|
||
```bash
|
||
# 1) Bring up an isolated network and an empty postgres (same image and account as CI).
|
||
docker network create artexko-db 2>/dev/null || true
|
||
docker run -d --name artexko-pg --network artexko-db \
|
||
-e POSTGRES_USER=artex -e POSTGRES_PASSWORD=artex -e POSTGRES_DB=artex \
|
||
postgres:16-alpine
|
||
until docker exec artexko-pg pg_isready -U artex -d artex >/dev/null 2>&1; do sleep 1; done
|
||
|
||
# 2) Pass the DSN to run the DB integration packages (the DSN host is the container name).
|
||
# To run only the package you fixed, replace ./agent/ with config, db, evidence, llmrec, or server.
|
||
docker run --rm --network artexko-db -v "$PWD":/src -w /src \
|
||
-v artexko-gomod:/go/pkg/mod -v artexko-gocache:/root/.cache/go-build \
|
||
-e ARTEX_PG_DSN='postgres://artex:artex@artexko-pg:5432/artex?sslmode=disable' \
|
||
golang:1.26 sh -c 'go test ./agent/ -count=1'
|
||
|
||
# 3) Clean up.
|
||
docker rm -f artexko-pg && docker network rm artexko-db
|
||
```
|
||
|
||
CI's `go-db` job **isolates each of these six packages with its own postgres** and forces them
|
||
to run before merge (`.github/workflows/ci.yml`). If you changed a DB integration package, we
|
||
recommend verifying that package directly with the method above before you open the PR.
|
||
|
||
### Frontend (web)
|
||
|
||
```bash
|
||
cd web
|
||
npm ci
|
||
npm run dev # dev server
|
||
npm run build # production build
|
||
npm run build:static # static-export build (merge gate; includes TypeScript type checking)
|
||
npm run check # Biome lint/format check (informational; not a merge gate yet, due to pre-existing debt)
|
||
npm run check:fix # auto-fix
|
||
```
|
||
|
||
Formatting and linting before commit are managed with Biome. `lint-staged` automatically runs
|
||
`biome check --write` on staged files.
|
||
|
||
### Full run (Docker Compose)
|
||
|
||
```bash
|
||
cp .env.example .env # set POSTGRES_PASSWORD
|
||
docker compose up -d # start artex + postgres → http://localhost:8787
|
||
```
|
||
|
||
---
|
||
|
||
## Contribution process
|
||
|
||
1. **Open an issue first.** For large changes it is better to align on direction via an issue
|
||
before you start. For small fixes (typos, links, obvious bugs) you can send a PR directly.
|
||
2. **Fork** the repository and create a topic branch. Prefix the branch name with the nature of
|
||
the change, as in `feat/...`, `fix/...`, `docs/...`, `i18n/...`.
|
||
3. Write the change and **run the relevant verification yourself.** For a Go change, make the
|
||
`build`/`vet`/`test` above pass. For a web change, make `npm run build:static` pass (it also
|
||
performs the merge gate and the TypeScript type checking). `npm run check` (Biome) still has
|
||
pre-existing lint debt inherited from upstream and is not a merge gate yet — `web.yml` runs it
|
||
only as an informational step — so you do not need to make all of it pass. Instead, just
|
||
confirm that **your change does not add new errors** (when you commit, `lint-staged`
|
||
automatically applies `biome check --write` to the files you staged). If you changed
|
||
documentation (`.md`), run `python3 -I scripts/check-doc-links.py` to confirm that in-repo
|
||
link/image references and document anchor (`#heading`) links are not broken. Anchors are built
|
||
from headings into slugs with the same rule as GitHub and matched, so if you change a heading's
|
||
text without also fixing the anchor links that pointed to it, it is caught here (CI's `docs`
|
||
workflow enforces the same check as a merge gate). This check is also wired as the `docs` hook in
|
||
the repository root's [`.pre-commit-config.yaml`](.pre-commit-config.yaml), so if you run
|
||
`pre-commit install` it runs automatically on every commit (it uses only the Python standard
|
||
library and no network, so it finishes without Docker).
|
||
4. **Open a PR.** Follow the [PR template](.github/PULL_REQUEST_TEMPLATE.md) for the title and
|
||
description, and write what you changed, why, and how you verified it. If you changed the UI,
|
||
attach screenshots.
|
||
5. For a user-facing change (feature, localization, documentation, detection rule, and so on),
|
||
add one line to the `[Unreleased]` section of the [changelog (CHANGELOG.en.md)](CHANGELOG.en.md).
|
||
Internal refactoring or test-only changes may be omitted.
|
||
|
||
### Commit messages
|
||
|
||
Follow the convention of the existing commit history. The format is `type(scope): description`,
|
||
and the description is written in Korean.
|
||
|
||
- `type`: `feat` · `fix` · `docs` · `chore` · `refactor` · `test` · `i18n`, and so on
|
||
- `scope`: the changed area (`agent` · `web` · `server`, and so on); optional
|
||
|
||
Examples.
|
||
|
||
```
|
||
feat(agent): 사용자 노출 출력을 한국어로 강제 (langDirective)
|
||
docs: 한국어 README 작성, 원본은 README.zh.md 로 보존
|
||
i18n(web): 대시보드 네비게이션 라벨 한국어 번역
|
||
```
|
||
|
||
---
|
||
|
||
## Contributing detection rules and detection tests
|
||
|
||
This repository also keeps, in [`detections/`](detections/), rules for **defending against and
|
||
detecting** autonomous AI attacks like ARTEX. It consists of deployable [Sigma](https://sigmahq.io)
|
||
rules ([`detections/sigma/`](detections/sigma/)), network [Suricata](https://suricata.io) rules
|
||
([`detections/suricata/`](detections/suricata/)), a [MITRE ATT&CK](https://attack.mitre.org/)
|
||
coverage layer ([`detections/attack/`](detections/attack/)), and tests that reproducibly prove
|
||
these rules actually fire ([`detections/tests/`](detections/tests/)). When you add or change a
|
||
detection rule, please honor the contract below. Seven test suites mechanically enforce much of
|
||
this contract, so if you change only a rule and do not update the tests/layer, the tests fail.
|
||
|
||
- **Ground every indicator in an observable fact.** The strings, User-Agents, and behavioral
|
||
thresholds a rule uses must be ones actually found in this repository's source, and must not be
|
||
inferred. State the source file that is the basis for the rule (for example, the `artex-enrich/1.0`
|
||
indicator is confirmed in `enrich/enrich.go`). The indicator-match tests
|
||
([`detections/tests/indicators/`](detections/tests/indicators/)) check that each indicator is
|
||
still present in both the upstream source and the rule, so if an upstream resync changes a source
|
||
string, the test fails unless you fix the rule along with it. If you change the machine-readable
|
||
indicator list ([`detections/indicators/artex_indicators.csv`](detections/indicators/artex_indicators.csv)),
|
||
also update the MISP event that carries those same indicators
|
||
([`detections/indicators/artex_indicators.misp.json`](detections/indicators/artex_indicators.misp.json)).
|
||
The MISP export test ([`detections/tests/misp/`](detections/tests/misp/)) enforces that the two
|
||
files match row by row and that the event is a valid MISP document loadable by pymisp.
|
||
- **State limitations honestly.** Write what a rule cannot catch and its false-positive potential
|
||
in the Sigma rule's `description` and in the Suricata rule's comments. If something is a general
|
||
hunting lead (for example, a destructive command) rather than an ARTEX-specific signature, say so,
|
||
so that a single hit does not get used to conclude the attacker is ARTEX.
|
||
- **Pass static validation.** A Sigma rule must pass the SigmaHQ validator criteria with zero issues
|
||
(`sigma check --validation-config detections/tests/sigma_lint/validators.yml`). Plain `sigma check`
|
||
runs only pySigma's core validators, so SigmaHQ conventions such as title casing, field/logsource
|
||
classification, and reference links are filtered only by this config. The four exceptions are
|
||
SigmaHQ monorepo conventions that do not fit a standalone rule set, and their rationale is recorded
|
||
in [`detections/tests/sigma_lint/validators.yml`](detections/tests/sigma_lint/validators.yml). A
|
||
Suricata rule must load cleanly with `suricata -T`.
|
||
- **Ship a reproducible test with it.** Prove that the rule fires (or that its structure is valid)
|
||
with a test under [`detections/tests/`](detections/tests/). Generate the input deterministically
|
||
each time rather than committing binaries to the repository; assert properties that are independent
|
||
of the engine version (firing exists, no false positives) exactly; and for figures that fluctuate
|
||
with the version, assert a lower bound and record the baseline separately. If you add or change a
|
||
Sigma correlation rule, the backend portability test
|
||
([`detections/tests/sigma_backends/`](detections/tests/sigma_backends/)) checks that the rule
|
||
converts across multiple backends, so keep it consistent with the backend-support description in
|
||
[`detections/README.md`](detections/README.md).
|
||
- **Update the ATT&CK layer with it.** If you add or change an `attack.*` tag on a rule, update the
|
||
techniques and scores in [`detections/attack/artex_navigator_layer.json`](detections/attack/artex_navigator_layer.json)
|
||
to match. The consistency test enforces a bidirectional rule↔layer match, so it fails if there is a
|
||
rule tag missing from the layer or a layer technique missing from the rules.
|
||
- **Do not include anything that reads as attack guidance.** The detection material in this repository
|
||
maintains a defense/detection posture only. We do not accept write-ups that aid an attack, such as
|
||
how to carry out an exploit or techniques for evading detection.
|
||
|
||
The eight test suites run as-is with only Docker, and do not commit their artifacts to the repository.
|
||
Each script exits with a non-zero code if any single assertion fails, so it can be dropped straight
|
||
into CI or a pre-commit hook.
|
||
|
||
```bash
|
||
detections/tests/sigma/run.sh # Sigma: sigma check + backend conversion + indicator preservation
|
||
detections/tests/sigma_match/run.sh # Sigma: atomic rules fire on malicious sample events, stay quiet on benign
|
||
detections/tests/sigma_lint/run.sh # Sigma: full SigmaHQ-convention validators + documented criteria
|
||
detections/tests/sigma_backends/run.sh # Sigma portability: does a correlation rule convert across backends
|
||
detections/tests/suricata/run.sh # Suricata: synthesize pcap → suricata -r → assert alert counts
|
||
detections/tests/attack/run.sh # ATT&CK: bidirectional layer ↔ rule consistency
|
||
detections/tests/indicators/run.sh # Indicators: rule's pinned indicators ↔ upstream source, both ways
|
||
detections/tests/misp/run.sh # MISP: indicator CSV ↔ MISP event sync + pymisp validity
|
||
```
|
||
|
||
To run all eight at once, use [`detections/tests/run-all.sh`](detections/tests/run-all.sh). It runs the
|
||
eight sequentially in the same order as CI, runs the rest to the end even if an earlier suite fails, then
|
||
prints a per-suite PASS/FAIL summary, and exits with a non-zero code if any one fails. An example of
|
||
wiring this runner directly as a pre-commit hook is in the repository root's
|
||
[`.pre-commit-config.yaml`](.pre-commit-config.yaml). If you install it with `pip install pre-commit &&
|
||
pre-commit install`, the runner runs only on commits that change detection rules or the upstream source
|
||
those rules pin (the same scope as CI), catching rule/test mismatches before push. The same config file
|
||
also includes the `docs` hook that checks in-repo link/image/anchor references (the `check-doc-links.py`
|
||
from step 3 of the contribution flow above).
|
||
|
||
These eight tests are run by the repository CI
|
||
([`.github/workflows/detections.yml`](.github/workflows/detections.yml)) on every push/PR that changes
|
||
anything under `detections/`. The indicator-match test also runs when the upstream source files those
|
||
indicators point to (`enrich/`, `selfupdate/`, `guard/`, `db/`, `cmd/artex/main.go`) change, catching the
|
||
case where an upstream resync changes a User-Agent, marker, or default port and silently makes a rule
|
||
stale. So a change that updates only a rule without updating the tests/layer, a rule that breaks a SigmaHQ
|
||
convention, or a rule that is inconsistent with the source shows up red in CI before merge.
|
||
|
||
The rule index and each rule's basis and limitations are in [`detections/README.md`](detections/README.md),
|
||
and the tests' assertions and how to run them are in [`detections/tests/README.md`](detections/tests/README.md).
|
||
|
||
---
|
||
|
||
## License
|
||
|
||
This project is distributed under the **GNU Affero General Public License v3.0 (AGPL-3.0)**. By
|
||
submitting a contribution, you are taken to **agree that your contribution is also released under
|
||
AGPL-3.0**. In particular, if you modify this project and provide it to users over a network (for
|
||
example, as an online service), you must disclose the complete corresponding source code to those
|
||
users. The full terms are in the [LICENSE](LICENSE) file.
|