Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7117bdd
ci: enforce release/label/branch workflow (project automation, labels…
overwrite00 Aug 3, 2026
b6331ae
chore(deps)(deps): bump cryptography from 49.0.0 to 50.0.0 (#101)
dependabot[bot] Sep 17, 2026
6614000
ci(deps)(deps): bump actions/labeler from 5 to 7 (#102)
dependabot[bot] Sep 17, 2026
c43d34f
chore(deps)(deps): bump the minor-and-patch group across 1 directory …
dependabot[bot] Sep 17, 2026
8d94293
docs: update dependency table and changelog for #101/#102/#104
overwrite00 Sep 17, 2026
44915e0
chore(deps)(deps): bump the minor-and-patch group across 1 directory …
dependabot[bot] Sep 17, 2026
904f27a
docs: update dependency versions for #105 (cryptography 50.0.1, pyins…
overwrite00 Sep 17, 2026
0fa342d
fix: resolve all 18 mypy type errors in NullifyPDF.py (#106)
overwrite00 Sep 17, 2026
53fd334
chore: bump version to 2.1.1-beta.1 for beta testing cycle (#107)
overwrite00 Sep 17, 2026
2a56a0d
fix: upload beta release assets sequentially instead of via softprops…
overwrite00 Sep 17, 2026
f558610
fix: set release title and apply sequential-upload fix to stable prom…
overwrite00 Sep 17, 2026
11ba22b
feat: fix manual redaction selection, extend AI PII recognition, add …
overwrite00 Sep 17, 2026
247c4d6
fix: preserve scanned-page image content when exporting redactions
overwrite00 Sep 17, 2026
4827026
feat: remove Lite/Full build split, add PDF reconstruction from resto…
overwrite00 Sep 18, 2026
4a5ec81
docs: remove leftover Lite/Full mention in OCR architecture section
overwrite00 Sep 18, 2026
6047767
chore: bump version to 2.2.0-beta.2 for beta testing cycle
overwrite00 Sep 18, 2026
aff67ff
fix: reconstruct every occurrence of a repeated placeholder, not just…
overwrite00 Sep 18, 2026
efb94b7
chore: bump version to 2.2.0-beta.3 for beta testing cycle
overwrite00 Sep 18, 2026
aed617a
fix: reconstruct scanned PDFs by stored redaction boxes, not text search
overwrite00 Sep 18, 2026
1f33e69
chore: bump version to 2.2.0-beta.4 for beta testing cycle
overwrite00 Sep 18, 2026
2a6d731
fix: make v1-map placeholder fallback search span block boundaries
overwrite00 Sep 18, 2026
538fdcd
chore: prepare 2.2.0 stable release
overwrite00 Sep 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: 🐛 Bug Report
description: Report a bug or issue you've encountered
title: "[BUG] "
labels: ["bug"]
labels: ["type:bug"]
assignees: []
---

Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: ✨ Feature Request
description: Suggest an idea for NullifyPDF
title: "[FEATURE] "
labels: ["enhancement"]
labels: ["type:feature"]
assignees: []
---

Expand Down
28 changes: 28 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
lang:python:
- changed-files:
- any-glob-to-any-file: "**/*.py"

type:docs:
- changed-files:
- any-glob-to-any-file:
- "**/*.md"
- "docs/**"

type:ci:
- changed-files:
- any-glob-to-any-file:
- ".github/workflows/**"
- ".github/dependabot.yml"

scope:core:
- changed-files:
- any-glob-to-any-file:
- "NullifyPDF.py"
- "privacy_core.py"
- "build_local.py"
- "setup_env.py"

scope:deps:
- changed-files:
- any-glob-to-any-file:
- "requirements.txt"
6 changes: 2 additions & 4 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ Describe what testing you've done:
- [ ] Tested on macOS
- [ ] Tested on Linux
- [ ] All tests pass locally: `pytest tests/ -v`
- [ ] Build succeeds locally: `python build_local.py --lite`
- [ ] Full OCR build checked when packaging/OCR changes: `python build_local.py --full`
- [ ] Build succeeds locally: `python build_local.py`

**Manual Testing Steps:**
1. Load PDF: [describe what PDF you used]
Expand Down Expand Up @@ -71,8 +70,7 @@ Any additional context that reviewers should know?
Before marking as ready, please ensure:

- [ ] Tests pass: `pytest tests/ -v`
- [ ] Build passes: `python build_local.py --lite`
- [ ] Full OCR build passes when packaging/OCR changes: `python build_local.py --full`
- [ ] Build passes: `python build_local.py`
- [ ] Code is clean and follows style guide
- [ ] All checkboxes above are complete
- [ ] You've tested your changes locally
Expand Down
69 changes: 50 additions & 19 deletions .github/workflows/beta-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ jobs:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-22.04, macos-latest]
variant: [lite, full]

steps:
- name: Checkout Code
Expand Down Expand Up @@ -58,20 +57,18 @@ jobs:
echo "NULLIFYPDF_BETA_SUFFIX=${TAG#*-}" >> "$GITHUB_ENV"

- name: Build
env:
NULLIFYPDF_BUILD_VARIANT: ${{ matrix.variant }}
run: python build_local.py

- name: Upload Artifact
uses: actions/upload-artifact@v7
with:
name: beta-build-${{ runner.os }}-${{ matrix.variant }}
name: beta-build-${{ runner.os }}
retention-days: 5
path: |
dist/NullifyPDF_v*_Windows_*.exe
dist/NullifyPDF_v*_macOS_*.zip
dist/NullifyPDF_v*_Ubuntu_*.deb
dist/NullifyPDF_v*_Fedora_*.rpm
dist/NullifyPDF_v*_Windows.exe
dist/NullifyPDF_v*_macOS.zip
dist/NullifyPDF_v*_Ubuntu.deb
dist/NullifyPDF_v*_Fedora.rpm

create_beta_release:
name: Create GitHub Beta Release
Expand All @@ -86,15 +83,49 @@ jobs:
pattern: beta-build-*
merge-multiple: true

- name: Release
uses: softprops/action-gh-release@v3
with:
prerelease: true
files: |
all-builds/NullifyPDF_v*_Windows_*.exe
all-builds/NullifyPDF_v*_macOS_*.zip
all-builds/NullifyPDF_v*_Ubuntu_*.deb
all-builds/NullifyPDF_v*_Fedora_*.rpm
body: "NullifyPDF beta release (build from develop). Includes Lite and Full OCR variants. Do not use in production. If validation succeeds, this build will be promoted to stable without rebuilding."
- name: Create release and upload assets sequentially
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
TAG="${GITHUB_REF#refs/tags/}"
REPO="${{ github.repository }}"
NOTES="NullifyPDF beta release (build from develop). Do not use in production. If validation succeeds, this build will be promoted to stable without rebuilding."

if gh release view "$TAG" --repo "$REPO" >/dev/null 2>&1; then
echo "Release $TAG already exists, uploading/replacing assets."
else
gh release create "$TAG" --repo "$REPO" --title "$TAG" --prerelease --notes "$NOTES"
fi

# Uploaded one at a time (not via softprops/action-gh-release's
# concurrent batch) because parallel uploads of these large
# binaries (100-300MB each) were timing out with an opaque
# "Error saving asset" and no per-file retry.
shopt -s nullglob
files=(
all-builds/NullifyPDF_v*_Windows.exe
all-builds/NullifyPDF_v*_macOS.zip
all-builds/NullifyPDF_v*_Ubuntu.deb
all-builds/NullifyPDF_v*_Fedora.rpm
)

if [ ${#files[@]} -eq 0 ]; then
echo "No release assets found to upload" >&2
exit 1
fi

for f in "${files[@]}"; do
echo "Uploading $f ..."
attempt=1
until gh release upload "$TAG" "$f" --repo "$REPO" --clobber; do
if [ "$attempt" -ge 3 ]; then
echo "Failed to upload $f after $attempt attempts" >&2
exit 1
fi
attempt=$((attempt + 1))
echo "Retrying upload of $f (attempt $attempt)..."
sleep 10
done
done
33 changes: 33 additions & 0 deletions .github/workflows/guard-main-source.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Guard Main Source Branch

on:
pull_request:
types: [opened, reopened, synchronize, edited]
branches:
- main

permissions:
contents: read

jobs:
check-source-branch:
name: Only allow PRs into main from develop
runs-on: ubuntu-latest
steps:
- name: Verify head branch is develop
run: |
HEAD_REPO="${{ github.event.pull_request.head.repo.full_name }}"
BASE_REPO="${{ github.repository }}"
HEAD_REF="${{ github.event.pull_request.head.ref }}"

if [ "$HEAD_REPO" != "$BASE_REPO" ]; then
echo "::error::PRs into main must come from this repository's develop branch, not a fork ($HEAD_REPO)."
exit 1
fi

if [ "$HEAD_REF" != "develop" ]; then
echo "::error::PRs into main are only allowed from the develop branch (got '$HEAD_REF'). Merge into develop first, then open the release PR from develop."
exit 1
fi

echo "[OK] PR into main originates from develop."
34 changes: 33 additions & 1 deletion .github/workflows/project-automation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
issues:
types: [opened, reopened]
pull_request:
types: [opened, closed, reopened]
types: [opened, closed, reopened, synchronize]

permissions:
issues: write
Expand All @@ -22,6 +22,8 @@ jobs:

steps:
- name: "Assign and Add to Project"
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
REPO="${{ github.repository }}"
TOKEN="${{ secrets.GH_PROJECT_TOKEN }}"
Expand Down Expand Up @@ -82,6 +84,28 @@ jobs:
"https://api.github.com/repos/$REPO/issues/$PR_NUM" > /dev/null
echo " Assigned"

# Etichetta in base al prefisso conventional-commit del titolo
TYPE_LABEL=""
case "$PR_TITLE" in
feat:*|feat\(*) TYPE_LABEL="type:feature" ;;
fix:*|fix\(*) TYPE_LABEL="type:bug" ;;
docs:*|docs\(*) TYPE_LABEL="type:docs" ;;
chore:*|chore\(*) TYPE_LABEL="type:chore" ;;
ci:*|ci\(*) TYPE_LABEL="type:ci" ;;
refactor:*|refactor\(*) TYPE_LABEL="type:chore" ;;
perf:*|perf\(*) TYPE_LABEL="type:chore" ;;
test:*|test\(*) TYPE_LABEL="type:chore" ;;
esac
if [ -n "$TYPE_LABEL" ]; then
echo " - Applying label $TYPE_LABEL..."
curl -s -X POST \
-H "Authorization: token $TOKEN" \
-H "Accept: application/vnd.github+json" \
-d "{\"labels\":[\"$TYPE_LABEL\"]}" \
"https://api.github.com/repos/$REPO/issues/$PR_NUM/labels" > /dev/null
echo " Labeled"
fi

# Aggiungi al Project (solo se opened o reopened)
if [ "$PR_ACTION" = "opened" ] || [ "$PR_ACTION" = "reopened" ]; then
echo " - Adding to Project..."
Expand Down Expand Up @@ -125,6 +149,14 @@ jobs:
fi
fi

- name: "Label by Changed Files"
if: github.event_name == 'pull_request'
uses: actions/labeler@v7
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
configuration-path: .github/labeler.yml
sync-labels: false

- name: "Workflow Summary"
if: always()
run: |
Expand Down
92 changes: 77 additions & 15 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,28 @@ jobs:
name: Promote latest beta artifacts to stable
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v7

- name: Verify CHANGELOG has an entry for this version
if: startsWith(github.ref, 'refs/tags/')
run: |
TAG="${GITHUB_REF#refs/tags/}"
VERSION="${TAG#v}"

if ! grep -qE "^## \[$VERSION\] - [0-9]{4}-[0-9]{2}-[0-9]{2}" CHANGELOG.md; then
echo "::error::CHANGELOG.md has no '## [$VERSION] - YYYY-MM-DD' heading. On develop, move the [Unreleased] content under this heading before tagging the stable release."
exit 1
fi

UNRELEASED_BODY=$(awk '/^## \[Unreleased\]/{flag=1;next}/^## \[/{flag=0}flag' CHANGELOG.md | sed '/^[[:space:]]*$/d')
if [ -n "$UNRELEASED_BODY" ]; then
echo "::error::CHANGELOG.md still has content under [Unreleased] that hasn't been moved to [$VERSION]. Update it on develop first."
exit 1
fi

echo "[OK] CHANGELOG.md has a clean [$VERSION] entry and an empty [Unreleased] section."

- name: Resolve target beta release
id: beta
env:
Expand All @@ -50,31 +72,71 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir -p stable-assets
# Patterns are deliberately tolerant of a trailing "_Full"/"_Lite"
# suffix (no underscore pinned before the extension) so a beta
# built before the lite/full split was removed can still be
# promoted to stable.
gh release download "${{ steps.beta.outputs.tag }}" --repo "${{ github.repository }}" --dir stable-assets \
--pattern "NullifyPDF_v*_Windows_*.exe" \
--pattern "NullifyPDF_v*_macOS_*.zip" \
--pattern "NullifyPDF_v*_Ubuntu_*.deb" \
--pattern "NullifyPDF_v*_Fedora_*.rpm"
--pattern "NullifyPDF_v*_Windows*.exe" \
--pattern "NullifyPDF_v*_macOS*.zip" \
--pattern "NullifyPDF_v*_Ubuntu*.deb" \
--pattern "NullifyPDF_v*_Fedora*.rpm"

- name: Strip beta suffix from filenames
run: |
cd stable-assets
# Drop any leftover "_Lite" assets from betas built before the
# lite/full split was removed: only the full variant is promoted.
rm -f *_Lite.* *_Lite
for f in *; do
new="$(echo "$f" | sed -E 's/-beta\.[0-9]+//')"
# Also drops the now-redundant "_Full" variant tag.
new="$(echo "$f" | sed -E 's/-beta\.[0-9]+//; s/_Full//')"
if [ "$f" != "$new" ]; then
mv "$f" "$new"
fi
done
ls -la

- name: Create Stable Release
uses: softprops/action-gh-release@v3
with:
files: stable-assets/*
prerelease: false
body: |
NullifyPDF stable release.
Promoted from beta `${{ steps.beta.outputs.tag }}` (already verified build, no rebuild).
Includes Lite and Full OCR variants for Windows, macOS, and Linux.
- name: Create stable release and upload assets sequentially
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
TAG="${GITHUB_REF#refs/tags/}"
REPO="${{ github.repository }}"
NOTES="NullifyPDF stable release.
Promoted from beta \`${{ steps.beta.outputs.tag }}\` (already verified build, no rebuild).
Available for Windows, macOS, and Linux."

if gh release view "$TAG" --repo "$REPO" >/dev/null 2>&1; then
echo "Release $TAG already exists, uploading/replacing assets."
else
gh release create "$TAG" --repo "$REPO" --title "$TAG" --notes "$NOTES"
fi

# Uploaded one at a time, not via softprops/action-gh-release's
# concurrent batch: parallel uploads of these large binaries
# (100-300MB each) were timing out with an opaque "Error saving
# asset" and no per-file retry (see beta-release.yml).
shopt -s nullglob
files=(stable-assets/*)

if [ ${#files[@]} -eq 0 ]; then
echo "No release assets found to upload" >&2
exit 1
fi

for f in "${files[@]}"; do
echo "Uploading $f ..."
attempt=1
until gh release upload "$TAG" "$f" --repo "$REPO" --clobber; do
if [ "$attempt" -ge 3 ]; then
echo "Failed to upload $f after $attempt attempts" >&2
exit 1
fi
attempt=$((attempt + 1))
echo "Retrying upload of $f (attempt $attempt)..."
sleep 10
done
done
Loading
Loading