Feat/0.3.0 239 save policy strength - #582
Merged
Merged
Conversation
Pinned invariant: no analyze, apply, or candidate-serialize path writes to PDFRepairTransactionOptions::sourcePath. The slot passed without a production change.
…239) Pinned invariant: PDFArtifactStore publishes an imported file at its digest-addressed path with write bits cleared, so the received input is a distinct, read-only identity.
) Pinned invariant: the slot passed without a production change. Its non-vacuity comes from three assertions inside it - the registry holds at least 7 operations, at least one of them declines the append path, and downsample-images declares full rewrite. A test-side mutation that inverted the loop's else-branch expectation failed on add-bleed, proving the branch is reached against a signed source.
document.redact now runs pdf::validateSaveRequest with a
fullRewrite("redaction removes prior content") requirement before it reads the
document, so the refusal does not depend on how much work the redaction would
have done, and it emits save-policy.refused with ProcessingFailure (4) instead
of silently overwriting the caller's input.
Also reformats PdfTool/pdftoolredact.cpp: the file was already clang-format
dirty at HEAD (exit 74), and the changed-file format gate checks touched files.
…yk (#239) add-bleed and rgb-to-cmyk wrote their candidate to the path the caller named with no policy guard, so `add-bleed received.pdf --output received.pdf --overwrite` rewrote the trusted input even though both operations declare saveAsNewArtifact. Move the request building and the refusal into one shared PDFToolAbstractApplication::validateOperationSaveRequest, route redact's inline block through it, and call it from add-bleed and rgb-to-cmyk with the policy their registry entry declares. A missing registry entry keeps the command working through the explicitly-undeclared policy. The guard runs before the document is read and before validateDestructiveOutput, so the refusal is not conditional on --overwrite and also covers --dry-run and --report. PdfTool/pdftoolrgbtocmyk.cpp was already dirty at HEAD for clang-format (case-labels, brace lists, namespace comments); formatted in this commit, no semantic change.
Cover add-bleed and rgb-to-cmyk the way redact is covered: the input path passed as its own output is refused with exit 4 and `save-policy.refused`, the Core message is the pinned trusted-input text, no output is recorded and the input stays byte-identical. The positive control in each slot re-runs the same invocation against a distinct output path and requires exit 0, so the guard cannot be satisfied by refusing the command outright. Both slots fail when the add-bleed guard is deleted (verified by mutation).
The reusable-linux.yml job now installs qpdf and poppler-utils, runs UnitTestsIncrementalSave with LOOP_SAVE_POLICY_EVIDENCE_DIR set so the signed incremental artifact is emitted, runs scripts/qualification/run_independent_validators.py with --claim structural and --claim signature, asserts inline that the run is passed and that every per-claim status is passed, and uploads the evidence JSON as the save-policy-independent-validation workflow artifact. The passing run is produced by the reusable-linux.yml job (step "Prove signed incremental save with independent validators") and is pending the first dispatch; CI cannot commit the evidence itself. This commit therefore records the honest local run at docs/evidence/session-15-save-policy/independent-validation-local.json (status incomplete, reason_code validator-not-installed for both claims), which never counts as a pass per docs/INDEPENDENT_VALIDATION.md. docs/INCREMENTAL_SAVE.md no longer claims the repository carries no signing fixture: the fixture, its generator, the byte-range and cost slots, and the CI-owned structural/signature claims are named.
Pinned invariant, not a defect fix: nothing in the tree sets an approval kind
or a rollback approved-output flag today, so the new
OperationHistoryTest::noSavePathProducesAnApprovedOutputRecord slot passes on
first run and guards the 0.3.0-B approval workflow (LOUPE-53). Before this
commit the suite had 16 slots and none of them named the invariant.
Two plan snippets were wrong against the code and are corrected here (the
assertions are stronger than the plan's, not weaker):
- PDFOperationHistoryEvent has no operationId member (it belongs to
PDFOperationHistoryExecution, pdfoperationhistory.h:100), so that line is
dropped; the operation identity stays pinned on
PDFRollbackPoint::operationId, which does exist.
- QVERIFY(!approval.isValid()) is false:
PDFApprovalRecord::isValid() means "well formed", and
PDFOperationHistoryStore::appendEvent refuses any event whose approval is
invalid (pdfoperationhistorystore.cpp:381), so the default record must be
valid. The pin is therefore kind == None plus every approval field empty,
plus a positive control that a record claiming a Human decision without
actor, decision or decision time is invalid. The gate that keeps a default
record out of the rollback path is isValid() && kind != None
(pdfoperationhistorystore.cpp:790).
Mutation evidence for non-vacuity: flipping PDFRollbackPoint::approvedOutput's
default to true fails exactly this slot ('!point.approvedOutput' returned
FALSE, 16 passed / 1 failed) and nothing else; reverted, the suite is
17 passed, 0 failed, 0 skipped.
docs/EDITOR_RECOVERY.md described a recovery service that is not in the tree. It now states that 2a19e2c deleted LoupeLibGui/pdfrecoverymanager.{h,cpp}; that the rest of the document is the contract to restore, not shipped behaviour; that UnitTests/tst_recoverytest.cpp compiles against a header that does not exist and is registered in no CMake target, so it neither compiles nor runs; that the approval half of the 0.3.0-A criterion is pinned by UnitTestsOperationHistory::noSavePathProducesAnApprovedOutputRecord; and that the restore half is tracked by #575. UnitTests/tst_recoverytest.cpp gains a // NOT COMPILED: header comment under the license block so the orphan cannot be mistaken for a running test. The file is kept as the specification and is deliberately still not added to a CMake target. python scripts/ci/check_source_integrity.py: "Source integrity policy passed." (exit 0).
Merge origin/dev into feat/0.3.0-239-save-policy-strength to unblock PR #582. Keep both save-policy test mappings (UnitTestsRedactVerifier from #582) and dev additions (UnitTestsRepairDiff, UnitTestsRepairOperatorAcceptance, UnitTestsPageBoxCorpus). Auto-merged dev release 0.2.1-alpha and page-box corpus work without touching save-policy write-boundary code. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Regenerate docs/generated/phase5-widgets-inventory.json so the Supply Chain Policy check passes after merging origin/dev (CMake target graph drift). Co-authored-by: michael berry <mberrys@users.noreply.github.com>
UnitTestsBleedStress parsed stdout as a flat preflight report, but PdfTool now emits schema_version 1 envelopes with the report under data.report. Align runPreflight() with OperatorAcceptance and PreflightCorpus helpers so failBleedPreflight sees check_id bleed again. No save-policy change. Co-authored-by: michael berry <mberrys@users.noreply.github.com>
Co-authored-by: michael berry <mberrys@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.