4.0 KiB
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; 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 — not a CLA. Add a
Signed-off-by: Your Name <your@email> line to each commit (git does this for
you with git commit -s). The repo is REUSE-compliant: every file
carries SPDX metadata, either inline or via .reuse/dep5. Run
reuse lint before pushing.
Build setup
# 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-formatis the style. Runclang-format -ion changed files; CI rejects drift. - clang-tidy checks are committed in
.clang-tidyand 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 — seecmake/FreePDFEditorHardening.cmake. These are on in release, not just debug. - No secrets in history.
gitleaksruns 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 §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)
- Push after every change. Work in progress goes to a branch — never sits uncommitted.
- Never commit to
maindirectly. Branch with afeat/,fix/,spike/, orchore/prefix;mainis protected. - Conventional Commits with the affected layer as a scope, e.g.
fix(L3): restore graphics state at splice boundary. - Large binaries via Git LFS in the separate
freepdfeditor-corpusrepo. - Tags are releases: annotated, signed, semver.
Reporting bugs
Use the Gitea issue tracker at
https://gitea.lm.je/ai-ad4/freepdfeditor/issues. For security
vulnerabilities, see SECURITY.md — do not open a public
issue for security reports.