Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
49 changes: 49 additions & 0 deletions .grype.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,55 @@
# stable Python 3.14 or Debian 13 packages become available upstream.

ignore:
# Approved by Adam Hernandez on 2026-09-26 only for the exact refreshed DHI
# runtime revisions below. These are accepted-risk exceptions, NOT fixes.
# Pullbox now strictly normalizes valid UTF-16 and rejects malformed surrogate
# input before its DefusedXML/Expat call sites. The libexpat1 copy also remains
# in the PDF helper dependency closure, where it parses trusted local config,
# not imported comic XML. Residual upstream-library risk remains until DHI
# ships fixed packages; all other High findings continue to block.
#
# Keep the existing libc review deadline of 2026-09-30 or the next base
# refresh, whichever comes first. Keep the existing Expat review deadline of
# 2026-10-07 or the next base refresh, whichever comes first. Remove these
# entries as soon as fixed stable packages are available.
# https://security-tracker.debian.org/tracker/CVE-2026-5435
# https://security-tracker.debian.org/tracker/CVE-2026-19499
# https://security-tracker.debian.org/tracker/CVE-2026-66046
# https://security-tracker.debian.org/tracker/CVE-2026-76956
# https://security-tracker.debian.org/tracker/CVE-2026-76957
# https://security-tracker.debian.org/tracker/CVE-2026-93990
- vulnerability: CVE-2026-5435
package:
name: libc6
version: 2.41-12+deb13u4+dhi1
type: deb
- vulnerability: CVE-2026-19499
package:
name: libc6
version: 2.41-12+deb13u4+dhi1
type: deb
- vulnerability: CVE-2026-66046
package:
name: libexpat1
version: 2.8.3-1~deb13u1+dhi4
type: deb
- vulnerability: CVE-2026-76956
package:
name: libexpat1
version: 2.8.3-1~deb13u1+dhi4
type: deb
- vulnerability: CVE-2026-76957
package:
name: libexpat1
version: 2.8.3-1~deb13u1+dhi4
type: deb
- vulnerability: CVE-2026-93990
package:
name: libexpat1
version: 2.8.3-1~deb13u1+dhi4
type: deb

# Renewed by Adam Hernandez on 2026-09-14 only for this DHI libc6 revision.
# Accepted risk, NOT a fix: Debian 13 still lists this TSIG-printing issue
# as vulnerable/no-DSA. Direct Pullbox callers were not found, but dependency
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: help bootstrap-worktree setup dev dev-local dev-docker dev-docker-up dev-docker-down dev-docker-logs dev-docker-shell dev-docker-seed prod-test-pull prod-test-up prod-test-refresh prod-test-down prod-test-logs prod-test-shell run lint format format-fix typecheck test test-unit test-slow test-integration test-api test-providers test-utilities test-a11y test-e2e test-e2e-chrome test-e2e-firefox coverage coverage-check migrate migration seed seed-full reset-db reset-password reset-import import-fixture performance-baseline direct-download-baseline validate runner-preflight release-changelog-check workflow-hygiene secret-scan security-ci ci-local docker-build-check docker-security-check docker-smoke ci-full ci-clean-room security-check pre-commit css-build css-watch clean
.PHONY: help bootstrap-worktree setup dev dev-local dev-docker dev-docker-up dev-docker-down dev-docker-logs dev-docker-shell dev-docker-seed prod-test-pull prod-test-up prod-test-refresh prod-test-down prod-test-logs prod-test-shell run lint format format-fix typecheck test test-unit test-slow test-integration test-api test-providers test-utilities test-a11y test-e2e test-e2e-chrome test-e2e-firefox coverage coverage-check migrate migration seed seed-full reset-db reset-password reset-import import-fixture performance-baseline library-navigation-baseline direct-download-baseline validate runner-preflight release-changelog-check workflow-hygiene secret-scan security-ci ci-local docker-build-check docker-security-check docker-smoke ci-full ci-clean-room security-check pre-commit css-build css-watch clean

VENV := .venv
PYTHON_BOOTSTRAP ?= python3
Expand All @@ -15,6 +15,7 @@ DEV_DOCKER_URL ?= http://127.0.0.1:$(DEV_DOCKER_PORT)
DOCKER_SMOKE_KEEP_ON_FAILURE ?= 0
PERFORMANCE_BASELINE_URL ?= $(DEV_DOCKER_URL)
PERFORMANCE_BASELINE_ARGS ?=
LIBRARY_NAVIGATION_BASELINE_ARGS ?= --profile ethan
TOOLS_DIR := .cache/tools
ACTIONLINT := $(TOOLS_DIR)/actionlint
GITLEAKS := $(TOOLS_DIR)/gitleaks
Expand Down Expand Up @@ -366,6 +367,9 @@ performance-baseline: ## Capture a JSON performance baseline for the active dev
$(PERFORMANCE_BASELINE_ARGS) \
--output data/performance/baseline.json

library-navigation-baseline: ## Benchmark Library navigation with a disposable scale fixture
$(PYTHON) scripts/benchmark_library_navigation.py $(LIBRARY_NAVIGATION_BASELINE_ARGS)

direct-download-baseline: ## Capture the offline DD-0 workload baseline
@mkdir -p data/performance
$(PYTHON) scripts/benchmark_direct_download_readiness.py \
Expand Down
57 changes: 50 additions & 7 deletions docs/development/IMPORT_REVIEW_RECOVERY.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ task-oriented:
all ready comics** selects the safe canonical set without requiring the user
to visit every deferred group. Detailed status tables remain available under
**Review details**.
- Dangerous archive content stays in **Cannot import**. **Acknowledge** excludes
every dangerous file shown for that series from the import, records the
decision, and leaves the source files and safe siblings unchanged.
- Unsupported extensions stay in **Cannot import** with the detected extension,
the supported comic types, and **Recheck** and **Skip** actions. Recheck may
adopt one exact same-folder, same-stem converted file after normal source and
safety validation; it never chooses between multiple replacements.
- Unclassified safety failures appear in **Fix source** with **Recheck** and
**Skip** because Pullbox has not established that the file is dangerous.
- Trusted, complete Mylar or ComicInfo Story Arc evidence may create a logical
Story Arc automatically. Inferred or incomplete arc evidence is retained for
later review and never blocks canonical comic import.
Expand Down Expand Up @@ -63,15 +72,19 @@ an ordinary numbered issue. Keep-in-place reference-root checks still apply
independently of discovery.

Steps 2 and 3 report available file records separately from missing references.
Missing references remain visible in review (in Info when no other issue needs
attention), but are not counted as available comics, archive safety decisions,
or unsettled file-review work. Durable
Every unresolved missing reference remains visible in the dedicated Missing
references lane, including when the same series has ready files in another lane.
It counts as an unsettled review decision until the user pairs it to a verified
replacement, restores and rechecks its recorded path, or explicitly skips the
reference. It is not counted as an available comic or archive safety decision. Durable
`scan_total_files` and `files_total` remain record totals for compatibility.
`files_present` and `files_missing_references` expose the split. Mylar batch
diagnostics also record the handling mode and reconciled-reference count.

A renamed source can replace a stale Mylar path only when one same-folder file
has an independent, agreeing ComicInfo issue ID. Reconciliation checks the
A renamed source can replace a stale Mylar path only when a same-folder file has
an independent, agreeing ComicInfo issue ID. When more than one proven candidate
exists, the user chooses the replacement and the background worker verifies that
exact selection before pairing it. Reconciliation checks the
issue publication year, not ComicInfo.Volume's series start year. A Mylar
ordinary-issue row may represent a collected volume only when its saved
filename explicitly identifies a volume. Conflicting IDs, numbers, publication
Expand Down Expand Up @@ -374,8 +387,7 @@ expired preview or any action whose row set changed after preview. Bounded,
recoverable actions use a normal confirmation; typed confirmation remains
reserved for permanent deletion. Mutations run in bounded database pages,
recompute import counters, and create import and security audit records.
Dangerous, unknown, and genuinely ambiguous outcomes remain manual-review
items.
Dangerous and genuinely ambiguous outcomes remain manual-review items.

Once cleanup is complete, **Archive results** hides the finished job from the
current history view without deleting its rows, logs, decisions, or rollback
Expand Down Expand Up @@ -565,6 +577,37 @@ rules but have no stale Mylar database references to repair. Missing-path copy
does not assume a file disappeared after the scan: it may never have existed
under the database's recorded name.

## Completed Recovery Checkpoints

`Recheck files` includes selected, confirmed files stranded under completed
series groups when their saved issue target is still intact. The signed request
captures their IDs and update timestamps. Recovery isolates those files into
retry groups, checkpoints each batch, and leaves skipped, unselected,
conflicting, or subsequently changed rows alone. Ordinary Step 4 source and
ownership checks still run before registration.

`Resolve and retry` for mixed folders queues background preparation rather
than applying the entire reconciliation in the HTTP request. Batches contain
at most 25 previewed resolutions; each mutation and cursor commit together,
with progress published afterward. Changed evidence is left for another review.
Only groups containing newly prepared files enter Step 4. Pause/restart resumes
the saved cursor, and Cancel preserves the original import and completed repairs.
Transient SQLite lock failures retry from that cursor; persistent contention
leaves the job stalled and resumable, not failed. Unrelated database errors are
not retried as lock failures.

Source rechecks retain a one-time size or single-page approval only when the
inspected file matches the approved signature. A mount device number may change;
the path, inode, size, and modification time may not. Inspection validates that
signature again so replacement races cannot inherit an old approval. Dangerous
archives remain blocked.

Legacy generic identity failures without recorded conflicts can be reinspected;
explicit identity conflicts remain manual. A previously approved mixed-folder
ComicInfo match rejected only for lacking an embedded issue ID can also be
rechecked. Fresh exact title, issue, type, and compatible date evidence must
agree with the saved target, without contradictory IDs or filename evidence.

## Content Outcomes

- `archive_no_pages`: there are no non-empty supported image members. A
Expand Down
Loading
Loading