freepdfeditor/CONTRIBUTING.md

4.0 KiB
Raw Blame History

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 Originnot 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-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 §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 https://gitea.lm.je/ai-ad4/freepdfeditor/issues. For security vulnerabilities, see SECURITY.md — do not open a public issue for security reports.