# Contributing to FreePDFEditor Thank you for your interest in contributing. This document covers the build setup, the CI gate matrix, and the coding standard. The full engineering plan lives at [`docs/plan.md`](docs/plan.md); source-control workflow is §13. ## Licensing Every contribution is licensed under **GPL-3.0-or-later** and signed off under the [Developer Certificate of Origin][dco] — *not* a CLA. Add a `Signed-off-by: Your Name ` line to each commit (git does this for you with `git commit -s`). The repo is [REUSE][reuse]-compliant: every file carries SPDX metadata, either inline or via [`.reuse/dep5`](.reuse/dep5). Run `reuse lint` before pushing. [dco]: https://developercertificate.org/ [reuse]: https://reuse.software/ ## Build setup ```bash # 1. Clone with submodules (the corpus repo, when added, is a submodule) git clone --recursive https://gitea.lm.je/ai-ad4/freepdfeditor.git cd freepdfeditor # 2. Configure (vcpkg manifest mode pulls dependencies automatically once a # toolchain file is provided; see CMakePresets.json) cmake --preset default # 3. Build cmake --build --preset default # 4. Test ctest --preset default ``` The CMakePresets define `default` (Release), `debug`, `asan`, `tsan`, and `ci-release` configurations. The CI matrix runs Linux/macOS/Windows × Debug/Release/ASan. ## Coding standard * **C++20**, no compiler extensions (`-std=c++20` / `/std:c++20`). * **clang-format** is authoritative — the committed `.clang-format` is the style. Run `clang-format -i` on changed files; CI rejects drift. * **clang-tidy** checks are committed in `.clang-tidy` and run in CI. * **Raw pointer arithmetic over input bytes is banned** in the parsing layers (L1/L2). Use bounded views (`std::span`-like). clang-tidy flags it; review blocks it. * **Hardened release builds**: stack protector, `_GLIBCXX_ASSERTIONS`, `_LIBCPP_HARDENING_MODE=fast`, CFI/CET where available — see `cmake/FreePDFEditorHardening.cmake`. These are on in release, not just debug. * **No secrets in history**. `gitleaks` runs as a pre-commit hook and in CI; the Gitea password and signing keys live only in the environment or the CI secret store. ## The gate matrix (every PR) From [`docs/plan.md`](docs/plan.md) §8.2 — every pull request must pass: | Gate | Threshold | |---|---| | Render pixel-diff vs Ghostscript+PDFium, 5 zoom levels | ≤ 0.1% differing pixels | | Own Skia renderer vs PDFium | ≤ 0.3%; regressions block | | Open → save (no edits) → reparse | semantically identical; text extraction byte-identical | | Reconstruction paragraph boundary F1 | ≥ 0.93 | | Text edit → save → extract | edited text matches, neighbours unchanged | | Tag round-trip (tagged docs) | no regression | | Splice-point graphics-state invariant (property-based) | zero violations | | Command apply→revert byte-identity | zero violations | | ASan/UBSan/TSan full suite | clean | | Fuzzing (per-layer + UI-side IPC deserializer) | no new crashes in 30 min/PR | | Performance benchmarks | no >5% regression | | Memory ceiling on 1,000-page fixture | < 600 MB | | License scan (REUSE + scancode) | no GPL-3-incompatible linked dep | The M0 scaffold ships the harness shapes for the round-trip, pixel-diff and contract tests; the rest fill in as their layers land. ## Source-control workflow (§13) 1. **Push after every change.** Work in progress goes to a branch — never sits uncommitted. 2. **Never commit to `main` directly.** Branch with a `feat/`, `fix/`, `spike/`, or `chore/` prefix; `main` is protected. 3. **Conventional Commits** with the affected layer as a scope, e.g. `fix(L3): restore graphics state at splice boundary`. 4. **Large binaries via Git LFS** in the separate `freepdfeditor-corpus` repo. 5. **Tags are releases**: annotated, signed, semver. ## Reporting bugs Use the Gitea issue tracker at . For security vulnerabilities, see [`SECURITY.md`](SECURITY.md) — do **not** open a public issue for security reports.