Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
7a8ec71
feat(loans): allow multiple physical copies per borrower
fabiodalez-dev Aug 20, 2026
40662cb
fix(loans): address multiplicity review findings
fabiodalez-dev Aug 21, 2026
d9436a6
fix(loans): centralize copy commitment policy
fabiodalez-dev Aug 21, 2026
027dd2a
refactor(loans): share open commitment states
fabiodalez-dev Aug 21, 2026
5d16a55
test(e2e): cover the multiple-copy loan desk flow end-to-end (#238)
fabiodalez-dev Aug 21, 2026
0f54a81
chore(release): bump to 0.7.64 and document multiple-copy loans (#238)
fabiodalez-dev Aug 21, 2026
4a421ce
test(e2e): restore the multiplicity setting byte-for-byte in cleanup
claude Aug 21, 2026
141fd3a
fix(loans): harden approval and pickup against out-of-house copies (#…
claude Aug 21, 2026
ebf0a1b
fix(reservations): queue eligibility, copyless books and admin edit g…
claude Aug 21, 2026
2e6a199
fix(loans): desk-flow and return-flow follow-ups to #368
claude Aug 21, 2026
c3d07b9
fix(circulation): serve every compatible hold per freed copy
claude Aug 21, 2026
76ac903
fix(notifications,cron): pickup-ready retry, email-less borrowers, cr…
claude Aug 21, 2026
5f61337
fix(ncip): partner enforcement, per-user loan resolution, full transa…
claude Aug 21, 2026
db8583a
docs(changelog): document the circulation review fixes and seed the n…
claude Aug 21, 2026
c03bd9e
test(mvcc): accept the eligibility batch size in the queue locking-re…
claude Aug 21, 2026
c2a1ba8
fix(static): satisfy PHPStan level 5 on the pickup-claim revert and t…
claude Aug 21, 2026
36847fa
fix(review): address CodeRabbit findings on #370
claude Aug 21, 2026
1b95747
test: align related-books responsive spec with the snap-strip layout
claude Aug 21, 2026
04ceda1
test: align ultra-wide related-books bound with the 1320px wrap cap
claude Aug 21, 2026
1f4a0bb
fix: harden pickup-notification claim and NCIP partner edge cases
claude Aug 21, 2026
c7f1266
fix(review): harden circulation and release readiness
fabiodalez-dev Aug 21, 2026
b573024
ci: document the attestations permission for zizmor
claude Aug 21, 2026
6616d3b
ci: define STDOUT/STDERR in stdin-fed PHP upgrade-smoke scripts
claude Aug 21, 2026
a5235e6
fix(review): close final circulation findings
fabiodalez-dev Aug 21, 2026
03d5538
test: arrange stale-predecessor fixtures in trigger-valid order
claude Aug 21, 2026
830376c
ci: drop route scope from the ZAP 13-digit ISBN allowlist
claude Aug 21, 2026
d4bb10b
fix: address CodeRabbit round on notifications, NCIP and release tooling
claude Aug 21, 2026
2f18d34
test: align static loan-edge-case contract with the 66-test suite
claude Aug 21, 2026
7fba566
test: gate multiple-copy-loans-238 on E2E_DB_NAME like real-world-25
claude Aug 21, 2026
21666c2
ci: harden browser regression gates
fabiodalez-dev Aug 21, 2026
35d7bb5
ci: distinguish shipped ISBN examples from PII
fabiodalez-dev Aug 21, 2026
c3b41c1
ci: constrain public ISBN example allowlist
fabiodalez-dev Aug 21, 2026
89b5ef9
fix: enforce overdue copy intervals symmetrically
fabiodalez-dev Aug 21, 2026
a6a0766
fix(ncip): audit idempotent check-ins
fabiodalez-dev Aug 21, 2026
71d6a4c
fix: align loan triggers with application date
fabiodalez-dev Aug 21, 2026
85306ff
fix(ncip): serialize request lifecycle mutations
fabiodalez-dev Aug 21, 2026
42a7fbc
fix(release): use supported paginated gh queries
fabiodalez-dev Aug 21, 2026
7728861
test: fetch the one-time loan submission token in loan-overlap C-group
claude Aug 21, 2026
beb139b
ci: drop unused google-chrome apt source before playwright install
claude Aug 21, 2026
2499f7c
fix(ci): remove unused Chrome apt source before refresh
fabiodalez-dev Aug 21, 2026
b2a4464
ci: verify flagged ZAP PII digits against fresh fetches
claude Aug 21, 2026
0136f21
ci: silence SC2034 in the ZAP re-fetch loop
claude Aug 21, 2026
61f1262
test: bind the application date on unit-suite DB connections
claude Aug 21, 2026
5b2a46e
fix(security): prevent CSRF tokens from resembling PII
fabiodalez-dev Aug 21, 2026
d7584d3
fix(ci): keep ZAP PII checks fail closed
fabiodalez-dev Aug 21, 2026
b00605d
fix(security): prevent CSP nonces from resembling PII
claude Aug 21, 2026
ff03dec
fix(security): harden CSP nonce validation
fabiodalez-dev Aug 21, 2026
661e9eb
fix: address CodeRabbit round on NCIP responses and release policy
claude Aug 21, 2026
c1929d0
fix: close final CodeRabbit review gaps
fabiodalez-dev Aug 21, 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
64 changes: 54 additions & 10 deletions .github/workflows/ci-browser-security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ jobs:

- name: Install Apache and packaging tools
run: |
# The hosted runner image ships Google's chrome-stable apt source,
# which these jobs never install from. Remove it before the first
# apt refresh so a mid-sync Google mirror cannot break the job.
sudo rm -f /etc/apt/sources.list.d/google-chrome.list
sudo apt-get update -q
sudo apt-get install -y apache2 libapache2-mod-php jq rsync unzip zip
sudo a2enmod rewrite headers env
Expand Down Expand Up @@ -160,9 +164,49 @@ jobs:
allow_issue_writing: false
artifact_name: zap-baseline-${{ github.run_id }}

- name: Test narrow ZAP bibliographic PII allowlist
run: bash tests/zap-pii-filter.test.sh

- name: Fail on medium or high ZAP alerts
run: |
test -s report_json.json || { echo "ZAP JSON report is missing"; exit 1; }
set -euo pipefail
identifiers_file="$RUNNER_TEMP/zap-catalogue-identifiers.json"
public_urls_file="$RUNNER_TEMP/zap-public-catalogue-urls.json"
public_examples_file="$RUNNER_TEMP/zap-public-example-identifiers.json"

MYSQL_PWD="$E2E_DB_PASS" mysql \
-h "$E2E_DB_HOST" -P "$E2E_DB_PORT" -u "$E2E_DB_USER" \
-N -B "$E2E_DB_NAME" -e '
SELECT identifier
FROM (
SELECT isbn13 AS identifier FROM libri WHERE deleted_at IS NULL
UNION
SELECT ean AS identifier FROM libri WHERE deleted_at IS NULL
) AS catalogue_identifiers
WHERE identifier REGEXP "^[0-9]{13}$"
ORDER BY identifier
' | jq -Rsc 'split("\n") | map(select(length > 0)) | unique' > "$identifiers_file"

# The single-quoted PHP program is intentional; its $variables must
# reach PHP literally rather than expand in the runner shell.
# shellcheck disable=SC2016
curl -fsS http://localhost:8081/sitemap.xml \
| php -r '
$xml = simplexml_load_string(stream_get_contents(STDIN), SimpleXMLElement::class, LIBXML_NONET);
if ($xml === false) { fwrite(STDERR, "Invalid sitemap XML\n"); exit(2); }
$urls = [];
foreach ($xml->url as $entry) { $urls[] = (string) $entry->loc; }
echo json_encode(array_values(array_unique($urls)), JSON_UNESCAPED_SLASHES), PHP_EOL;
' > "$public_urls_file"

# Translation dictionaries are intentionally inlined client-side.
# Extract only canonical, explicitly named ISBN example keys. The
# checked-in jq program requires a full 978/979 match and a valid
# ISBN-13 checksum, so unrelated numbers and longer substrings cannot
# become origin-wide exceptions.
jq -f scripts/ci-zap-public-isbn-examples.jq \
locale/it_IT.json > "$public_examples_file"

# OWASP ZAP rule 10062 (PII Disclosure) is allowlisted NARROWLY, never
# globally. A book catalogue renders ISBN/EAN-13 identifiers on its
# bibliographic pages, and a 13-digit code inherently collides with the
Expand All @@ -171,15 +215,15 @@ jobs:
# 413167 is a Visa range). An alert is ignored ONLY when EVERY instance
# is a 13-digit number on a bibliographic route — a real card leak
# (15/16 digits) or a 13-digit value on any other page still fails the
# build. Real secret/PII exposure is also covered by the secret-scanning,
# Semgrep and CodeQL jobs; every other medium/high alert stays blocking.
FILTER='def is_isbn_fp: (.pluginid // "") == "10062" and ([ .instances[]? | ((.evidence // "") | test("^[0-9]{13}$")) and ((.uri // "") | test("/(auteur|author|autor|autore|book|buch|catalog|catalogo|catalogue|editore|editori|genere|genre|katalog|libro|libri|livre|publisher|verlag)"; "i")) ] | (length > 0 and all)); [ .site[]?.alerts[]? | select((.riskcode | tonumber) >= 2) | select(is_isbn_fp | not) ]'
blocking=$(jq "$FILTER | length" report_json.json)
if [ "$blocking" -gt 0 ]; then
jq -r "$FILTER"' | .[] | "[" + (.riskdesc // "") + "] " + (.alert // "") + ": " + (.desc // "")' report_json.json
exit 1
fi
echo "ZAP found no blocking medium/high passive-scan alerts (allowlisted: 13-digit ISBN/EAN codes on bibliographic pages)"
# build. The checked-in filter also requires GET with empty param/attack,
# an exact registered route (canonical URLs come from the live sitemap)
# when evidence is a live catalogue identifier. The only route-wide
# exception is the exact public example strings shipped in the inlined
# translation dictionaries. Real secret/PII exposure is also covered
# by secret scanning, Semgrep and CodeQL; every other medium/high alert
# stays blocking.
bash scripts/ci-check-zap-report.sh \
report_json.json "$identifiers_file" "$public_urls_file" "$public_examples_file"

- name: Upload browser and server diagnostics
if: always()
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/ci-deep-regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ jobs:

- name: Install Apache, PHP module, MySQL client and mail transport
run: |
# This job never installs Google Chrome. Remove its hosted-runner
# apt source before the first refresh so mirror syncs cannot break CI.
sudo rm -f /etc/apt/sources.list.d/google-chrome.list
sudo apt-get update -q
sudo apt-get install -y apache2 libapache2-mod-php default-mysql-client msmtp-mta
sudo a2enmod rewrite headers env
Expand Down Expand Up @@ -279,6 +282,9 @@ jobs:
persist-credentials: false
- name: Install Apache and PHP module
run: |
# This job never installs Google Chrome. Remove its hosted-runner
# apt source before the first refresh so mirror syncs cannot break CI.
sudo rm -f /etc/apt/sources.list.d/google-chrome.list
sudo apt-get update -q
sudo apt-get install -y apache2 libapache2-mod-php default-mysql-client
sudo a2enmod rewrite headers env
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/ci-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ jobs:
# supports PHP >= 8.1, so the Ubuntu mod_php package is sufficient here.
- name: Install Apache2 + mod_php
run: |
# This job never installs Google Chrome. Remove its hosted-runner
# apt source before the first refresh so mirror syncs cannot break CI.
sudo rm -f /etc/apt/sources.list.d/google-chrome.list
sudo apt-get update -q
sudo apt-get install -y apache2 libapache2-mod-php
sudo a2enmod rewrite headers env
Expand Down
Loading