40 Commits
Author SHA1 Message Date
a047c6ba09 chore: resolve SonarCloud maintainability issues (#4356)
* chore: resolve SonarCloud maintainability issues

* fix(packaging): use verify_sha256 helper function

* style: cargo fmt

* fix: restore wildcard imports and fix method-reference type errors

Revert the glob-import expansions (they missed SomIndices and left unused
imports), revert char::is_ascii_digit where the iterator yields char by
value, and pass the content slice to prune_doomed_xobjects as &[Vec<u8>].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep XObject decodability check without binding content in interp

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dylan Taylor <dylan@craftmaker.dev>
2026-10-23 23:28:18 -04:00
Dylan M. Taylor a2ec27b477 ci(sonar): don't cancel superseded runs on main, so coverage is published (#4321) 2026-10-23 17:06:26 -04:00
Dylan M. Taylor aea5e78e66 release: the git-sources gate moves into craft-common-actions (storytold/craft-common-actions#78) (#4292)
The check is shared at release.yml@main now; keep only the reusable call.
2026-10-23 14:41:20 -04:00
Dylan M. Taylor 60643020b6 Merge pull request #4244 from dylanmtaylor/fix/high-severity-redact-sign
fix(redact,sign,cos): close the still-open high-severity scan findings
2026-10-23 10:25:51 -04:00
Dylan M. Taylor 5162da1b9f fix(sign): a widget counts as signed only when its /V resolves to a dictionary 2026-10-23 10:22:33 -04:00
Dylan M. Taylor 39ee93fe70 fix(redact,sign): address review — pop-up replies, signed-role deletions, widget role from signed revision 2026-10-23 10:11:10 -04:00
Dylan M. Taylor dad86bf9f5 fix(redact,sign,cos): close high-severity findings from the agent scan
Redact: refuse Redact marks written in place; remove replies and pop-ups listed on
other pages; delete form fields by object, not name; resolve Do by its last operand
like the renderer; sanitize drops PCAdded and flattens widgets before hidden-content
cleanup. Sign: freed signed objects and edits to an already-signed widget are
modifications. Cos: only reading trusts /Type /XRef to skip encryption.
2026-10-23 10:11:10 -04:00
Dylan M. Taylor 90bd6660f7 Merge pull request #4220 from Jayesh-Prajapati9/chore/ctutils-rustsec-2026-0385
M14: update ctutils to 0.4.5 for RUSTSEC-2026-0385
2026-10-23 10:11:03 -04:00
Dylan M. Taylor 0dc77fe4ed Merge pull request #4129 from aiongg/fix/coderabbit-c5-forms-misc
fix(xfdf, sign, preflight, engine, forms, measure, annot): bound repeated work in form exchange, preflight and export, and check what imports and time stamps claim
2026-10-22 22:50:29 -04:00
Dylan M. Taylor 5f7b9e241b Merge pull request #4109 from aiongg/fix/coderabbit-a1-audit
fix(audit): find covers the audit missed, bound its work and honour the copy permission
2026-10-22 22:50:24 -04:00
Dylan M. Taylor 7fa38de186 Merge pull request #4170 from dylanmtaylor/fix/sonar-shell-scripts
fix(packaging): use [[ tests and name positional parameters (SonarCloud shelldre:S7688, S7679, S7682, S131)
2026-10-22 22:48:47 -04:00
Dylan M. Taylor 1d29f0673c Merge pull request #4169 from dylanmtaylor/chore/sonar-scope-vendor-and-spec-hashes
chore(sonar): exclude vendored crates and the spec-mandated MD5/RIPEMD-160 (SonarCloud rust:S4790)
2026-10-22 22:48:42 -04:00
Dylan M. Taylor e93f11e81e fix(packaging): use [[ tests and name positional parameters in the scripts (SonarCloud shelldre:S7688, S7679, S7682, S131)
Every packaging script runs under bash, so [[ ]] is available. Name the positional
parameters of sha256, render and has, end env.sh's functions with an explicit return
(bare, so the exit status is unchanged), and give the build-label case a default arm.
2026-10-22 22:40:05 -04:00
Dylan M. Taylor bd9030b271 chore(sonar): exclude vendored crates and the spec-mandated MD5/RIPEMD-160 (SonarCloud rust:S4790)
vendor/ is third-party code kept close to upstream (vendor/README.md), so SonarCloud's
186 findings there are not ours to restyle. MD5 in crates/crypt is what ISO 32000's
standard security handler mandates, and RIPEMD-160 in crates/sign is a digest existing
signatures can name; both S4790 findings are scoped to those two files.
2026-10-22 22:36:03 -04:00
Dylan M. Taylor 7345e5f5de Merge main into fix/coderabbit-a1-audit
Keep this branch's budgeted audit() and read lines with main's
glyph_text_lines, so /ActualText cannot hide text under a cover.
2026-10-22 22:20:45 -04:00
Dylan M. Taylor 07a9109fed Merge remote-tracking branch 'origin/main' into HEAD 2026-10-22 22:07:20 -04:00
Dylan M. Taylor 93b25f67a6 Merge main into fix/coderabbit-c5-forms-misc
Keep the Ops iterator from this branch and carry main's long-number skip
(MAX_RETRIED_TOKEN) into its operand error path.
2026-10-22 22:07:19 -04:00
Dylan M. Taylor de91632934 Merge pull request #4151 from aiongg/fix/coderabbit-c2-edit-organize
fix(edit,organize,create): bound the work hostile files cause in editing, page organizing and image import
2026-10-22 21:57:13 -04:00
Dylan M. Taylor 684226713a Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/audit/src/tests.rs
2026-10-22 21:42:41 -04:00
Dylan M. Taylor d31a96f46f Merge pull request #4121 from aiongg/fix/coderabbit-c1-js-xfa
fix(js, xfa): bound the text and work that form scripts and XFA data can multiply
2026-10-22 21:39:08 -04:00
Dylan M. Taylor 8ee1ac0c58 Merge pull request #4117 from aiongg/fix/coderabbit-b-caps
fix(limits): bound the decoding and listing work that repeated references and small inputs multiply
2026-10-22 21:38:59 -04:00
Dylan M. Taylor 3cee9f338f Merge pull request #4128 from aiongg/fix/coderabbit-c4-core
fix(cos, content, filters, crypt, model, render, print, a11y): bound the work that repeated keys, streams and page values multiply
2026-10-22 21:38:37 -04:00
Dylan M. Taylor f7a3a52fad Merge pull request #4114 from aiongg/fix/coderabbit-b-shared
fix(cos): one decode budget per page walk, so repeated stream references cannot multiply decoding
2026-10-22 21:38:15 -04:00
Dylan M. Taylor 80b7d21525 fix: add generic font-family fallbacks in demo (SonarCloud css:S4649)
Each font-family in assets/demo/showcase.html named only a specific font with
no generic fallback. Add an appropriate generic (serif/sans-serif/monospace/
cursive/math) so text still renders if the specific face is unavailable.
2026-10-22 07:09:59 -04:00
Dylan M. Taylor dbc7130b36 ci: pin GitHub Actions to full commit SHA (SonarCloud githubactions:S7637) (#3932)
Pin third-party actions to full-length commit SHAs (with version comments)
instead of mutable tags/branches to prevent supply-chain tampering via
retagged releases. Resolves SonarCloud rule githubactions:S7637.
2026-10-21 20:14:11 -04:00
Dylan M. Taylor 78ef66636d security: enforce HTTPS on curl downloads (SonarCloud S6506) (#3933)
Add --proto '=https' to curl invocations so redirects cannot downgrade to
plaintext HTTP. Resolves SonarCloud S6506 (shell/docker/githubactions).
2026-10-21 20:13:46 -04:00
Dylan M. Taylor 606c560d24 Use chrono instead of hand-rolled UTC conversion (#3824)
* Use chrono for UTC/calendar conversion instead of hand-rolled copies

Replaces the hand-rolled civil_from_days/days_from_civil copies and the
leap-year/month math around them (log timestamp, PDF /Info dates, ASN.1
UTCTime/GeneralizedTime, FormCalc Date/Num2Date, the Combine modified-time
stamp, the form date picker, and the demo-PDF timestamps) with chrono as a
workspace dependency. The engine's existing chrono (clock) is lifted to the
workspace. Every output format is unchanged and pinned by tests. CLAUDE.md now
says time goes through chrono.

Follow-up to storytold/cadcraft#1785

* Guard chrono date paths: no panic on overflow, no '+' on 5-digit years

Systemic chrono follow-ups to the UTC/calendar PR:

- logging::timestamp and combine_ui::utc_stamp dropped chrono's
  From<SystemTime> (which unwraps internally and panics on a clock past
  year 262143) for the fallible DateTime::from_timestamp, reading an
  out-of-range clock as the epoch, as the old clamping code did.
- timestamp, utc_stamp, pdf_date and the xtask Stamp now write the year
  with {:04} instead of %Y, which prefixes a '+' before years past 9999;
  the old hand-rolled code wrote the plain zero-padded year.
- forms_ui calendar navigation and length, and formcalc days_in, use
  checked_add for the December year successor so y + 1 can't overflow at
  i32::MAX / i64::MAX (reachable from a parsed or persisted date).

Docstrings added to the chrono-touched civil_from_days and Time::from_unix
for the docstring-coverage gate. Tests cover the out-of-range-epoch and
10000-01-01 cases for each.

* Don't build an unrepresentable SystemTime in the far-future test

UNIX_EPOCH + Duration::from_secs(u64::MAX / 2) overflows Windows'
SystemTime and panicked before timestamp() ran, failing the Windows
test job. Build it with checked_add and only assert where it exists.

* Keep FormCalc dates exact past chrono's range

MAX_DAYS accepts day numbers up to 1e8 (years past 270000), but NaiveDate
stops near ±262143, so Num2Date(99000000) and Format fell back to
1900-01-01. days_from_civil, civil_from_days and days_in now have chrono
convert within the date's 400-year Gregorian cycle and add whole cycles
back (via i128), which gives the pre-chrono results for every year. Tests
cover accepted inputs past chrono's range on both sides of the epoch,
through Num2Date and Format, with values from the old formula.

* Bump rustls-webpki and webpki-root-certs for RUSTSEC-2026-0382/0383

rustls-webpki 0.103.15 -> 0.103.16 and webpki-root-certs 1.0.9 -> 1.0.10
(both semver-compatible, lockfile only) drop the distrusted emSign
intermediates and root. Only these two entries change; cargo deny check
advisories passes. Upstream main fails the same check.

* logging/cos/sign/combine/demo: keep extended-year dates, no epoch fallback

For consistency with the stricter no-epoch-fallback rule now agreed across the sibling
chrono PRs (wordcraft#3427, filmcraft#2662): `DateTime::from_timestamp(..).unwrap_or_default()`
changes a timestamp the old code converted past chrono's year 262143 range — it collapses
to 1970-01-01 instead of the real proleptic-Gregorian date. The FormCalc Num2Date path was
already fixed (FredApps approved); this applies the same fix to every remaining conversion.
Each site uses the 400-year Gregorian cycle (146_097 days) with chrono as the only calendar
logic: chrono converts the day within one cycle, whole cycles carry in the year (i128,
saturated into i64). PDF/ASN.1 format-specific year handling is kept exactly as the old code
had it. Verified the cycle result equals the old formula across a wide range and at the extremes.

- apps/pdfcraft/src/logging.rs `timestamp`: cycle `civil_from_days(u64)`; pre-1970 epoch clamp
  and ms/time-of-day format kept. Pins: +10_000_000_000_000 s -> 318857-05-20T17:46:40.000Z
  (was 1970); checked_add u64::MAX/2 s -> 292277026596-12-04T15:30:07.000Z (was epoch).
- crates/cos/src/writer.rs `pdf_date` (i64): cycle converter, no year clamp (old code wrote `y`
  as-is, so a negative year keeps its sign). Pins: pdf_date(10_000_000_000_000)="D:3188570520174640Z",
  pdf_date(-10_000_000_000_000)="D:-3149180813061320Z".
- crates/sign/src/der.rs `Time::from_unix` (i64): cycle converter; the `year` field is a u32, so
  the year is cast `as u32` (wrapping) exactly as the old code did — ASN.1 year width preserved
  byte-for-byte. Pins: from_unix(10e12).year=318857, from_unix(-10e12).year=4_294_652_378,
  from_unix(i64::MAX).year=219_250_468, from_unix(i64::MIN).year=4_075_720_767.
- crates/ui-egui/src/combine_ui.rs `utc_stamp` (u64): cycle converter; pre-1970 epoch clamp kept.
  Pins: utc_stamp(10e12)="318857-05-20 17:46 UTC", u64::MAX/2 s="292277026596-12-04 15:30 UTC".
- xtask/src/demo_pdf/pdf.rs `Stamp::from_unix` (i64): cycle converter, no year clamp. Pins:
  from_unix(10e12).iso="318857-05-20T17:46:40Z"/.pdf="D:3188570520174640Z",
  from_unix(-10e12).iso="-314918-08-13T06:13:20Z".

cos/sign/xtask built, tested (pdf_dates_are_utc_and_byte_identical, der::tests::times,
stamps_round_trip), fmt and clippy clean. pdfcraft-ui-egui and the pdfcraft app can't link
here (unrelated LLVM intrinsic bug in the rten-gemm dependency, 1.98.1), so their logging and
combine_ui functions + tests were copied verbatim into a scratch crate with chrono 0.4.45 and
pass there; fmt --check clean on all five packages. CI builds these on all platforms.

* Don't build a year-318857 SystemTime unchecked in the logging test

Windows' SystemTime only reaches about year 30828, so
UNIX_EPOCH + Duration::from_secs(10_000_000_000_000) panicked before
timestamp() ran and failed the Windows test job. Build it with
checked_add and assert where the platform can hold it. The year-10000
case fits everywhere and stays unconditional.

* Name the 400-year range extension as the one exception to the time rule

The rule said never to hand-roll calendar math, but the range fix
(shifting by whole 400-year Gregorian cycles so dates past chrono's year
range keep their old output) is cycle arithmetic, so the rule and the code
disagreed. The rule now names that exception: the library still computes
month, day and time, and only whole cycles are carried in the year.

* Say the library computes month and day; time-of-day is plain arithmetic

Narrows the range-extension wording: the date library computes the
calendar fields, and splitting seconds into hours, minutes and seconds
is ordinary arithmetic, which is what the code does.
2026-10-21 19:36:46 -04:00
Dylan M. Taylor b1bf1cf01f ci: add sonar-project.properties for CI-based analysis
Marks the project ineligible for SonarCloud Automatic Analysis, resolving the
CI-vs-automatic-analysis conflict so the SonarCloud workflow succeeds.
2026-10-21 16:00:45 -04:00
Dylan M. Taylor 30b8c60b55 ci: add SonarCloud scan via shared reusable workflow
Calls storytold/craft-common-actions/.github/workflows/sonarcloud.yml@main
with secrets: inherit. Adds SonarCloud badge to README where missing and
removes the redundant sonar-project.properties (config now passed by the
reusable workflow).
2026-10-21 15:47:03 -04:00
Dylan M. Taylor 4164951453 Merge pull request #2753 from dylanmtaylor/ci/shared-nix-workflow
ci: switch to shared nix workflow from craft-common-actions
2026-10-21 03:59:40 -04:00
Dylan M. Taylor d7481cca6e Merge remote-tracking branch 'origin/main' into pr-2753
# Conflicts:
#	.github/workflows/nix.yml
2026-10-21 03:41:36 -04:00
Dylan M. Taylor 59a5a83774 docs: add SonarCloud and CodeRabbit badges to README (#3271)
* docs: add SonarCloud and CodeRabbit badges and standardize to flat-square

* docs: put SonarCloud and CodeRabbit badges on their own line
2026-10-20 11:29:59 -04:00
Dylan M. Taylor a8cd797a91 ci: configure Dependabot for Cargo and GitHub Actions (#3304)
* ci: configure Dependabot for Cargo and GitHub Actions

* ci: add Cargo update entry for /crates/filters/fuzz in Dependabot

* ci: consolidate Cargo Dependabot directories in pdfcraft
2026-10-18 15:11:14 -04:00
Dylan M. Taylor 98cbd38a8e Merge pull request #3161 from dylanmtaylor/chore/drop-competitor-references
docs: drop references to competing commercial software
2026-10-18 11:31:27 -04:00
Dylan M. Taylor 9a7824557e docs: use generic office terms and clarify fidelity harness and parity tracking reference 2026-10-18 10:49:21 -04:00
Dylan M. Taylor feb6c38580 docs: drop references to competing commercial software 2026-10-18 10:48:33 -04:00
Dylan M. Taylor cfb71d850e ci: switch to shared nix workflow from craft-common-actions 2026-10-15 23:57:29 -04:00
Dylan M. Taylor 8fa6fecf70 ci: add nix check workflow 2026-10-15 21:17:37 -04:00
Dylan M. TaylorandBrandon Thomas 2ec7102035 chore: bump github actions to fix Node 20 deprecation warnings (#641)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-11 14:39:33 -04:00
Dylan M. Taylor 2316a8c419 ci: refactor workflows to use storytold/craft-common-actions (#1073)
* ci: refactor workflows to use reusable artcraft-common-actions

* ci: point reusable workflows to storytold/craft-common-actions

* ci: pin storytold/craft-common-actions to commit 27a978f and pass secrets explicitly

* ci: use @main (unpinned) for craft-common-actions with explanation comment
2026-10-11 11:51:25 -04:00