Use case: batch sign queue (multi-file, progress, manifest) #9
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
EduarD3V/AutoFirme#9
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Use case: drop N files, queue them, sign sequentially with chosen cert, per-file status (pending/signed/error), zip download of results + manifest.json (filename, sha256, timestamp, format).
Reference: decompiled/sources/es/gob/afirma/signers/batch/ (SignBatch, 9 classes) — mirror its manifest semantics.
Acceptance:
Depends on #6.
UNBLOCK NOTICE: dependency policy relaxed — do not wait for #5 to merge. Work against this interface contract (web/src/lib/certs.ts, being finalized in #5):
Until #5 lands: mock LoadedCert in your branch (test RSA/EC key + self-signed cert generated at test time via openssl/node:crypto — commit no binaries). Test fixtures for golden vectors come from reference implementations (openssl for CAdES, xmlsec1 for XAdES) or generated by scripts at test setup. Resolve merge conflicts vs bullet-develop at integration; keep web/src/lib/certs.ts imports behind a thin adapter if the API shifts.
bullet: coder launched on branch
issue/9-use-case-batch-sign-queue-mult(modelnan/deepseek-v4-flash).bullet: coder session died — relaunched from committed state (branch
issue/9-use-case-batch-sign-queue-mult).Claimed — branch
issue/9-use-case-batch-sign-queue-mult, HEAD62dc44e. Branch already carries the full #9 implementation from earlier sessions; doing: independent re-verification at this HEAD (gates + fresh browser batch run), fix anything found, then report.Plan — Issue #9: batch sign queue (multi-file, progress, manifest)
Restated goal
Step 1 of the SPA stops meaning "one file": the user drops N files (drop zone or picker), they
become a queue, and pressing sign processes them one after another with the certificate chosen
in step 2. Each queue entry carries its own status (
pending → signing → signed | error), shownlive, and a failing file is recorded as
errorwithout aborting the rest. When the run ends theuser downloads a ZIP holding one signed output per signed document plus
manifest.jsonwhose fieldsmirror AutoFirma's batch manifest.
Done =
pnpm test+pnpm check+pnpm buildgreen, the queue provably sequential (onesignature in flight), resumable (file 2 fails ⇒ files 1 and 3 still signed), the manifest fields
traceable to the decompiled reference, and every produced signature + the ZIP independently
verified (
openssl cms -verify,unzip -t,sha256sum) — per AGENTS.md's crypto rule.Scope decision (this session)
The issue declares a dependency on #6, and this branch was first written against a
nullsigner seam because #6 had no commits in the base. #6 now exists locally
(
issue/6-use-case-cades-sign-in-browser, stacked on #5). To meet the acceptance criterion"e2e test: 3-file batch all signed" with a real signature engine rather than a stand-in, this
branch is stacked on #5+#6 (merge commit
a948238, same convention #6 itself used), and thequeue is wired to
signCadesDetached.New/changed files
web/src/lib/zip.tsweb/src/lib/batch.tscreateBatchQueuestore,runBatch,buildManifest,buildZip,sha256Hexweb/src/lib/components/BatchQueue.svelteweb/src/lib/batch.test.tsopenssl cms -verifyweb/scripts/verify-batch-zip.mjsunzip -t+sha256sumcross-check of the archiveweb/src/lib/App.svelteFile[], renders the queue, engine adapter oversignCadesDetached(#6)web/src/lib/sign.tssigningAlgorithmName()(JCA name for the manifest),implementedflag on formatsweb/src/lib/components/FileDrop.sveltemultiple; hands over every dropped/picked fileweb/src/lib/i18n.tsweb/src/lib/App.test.tsweb/src/lib/components/{SignButton,ResultCard}.svelteweb/README.md,web/package.jsonpnpm verify:zipscriptNot touched:
decompiled/**(read-only reference),docs/**,Containerfile,Caddyfile,web/vite.config.ts, routes,components/{FileDrop,FileCard,CertPicker}(exceptmultiple),keystore.ts/pkcs12.ts/x509.ts/cms.ts/asn1.ts(#5/#6, taken as-is from the merge).Ordered tasks (each verified by one command)
zip.ts(ZIP writer) — verified bypnpm verify:zip(unzip -t+sha256sum).batch.ts(store machine, run loop, manifest, ZIP) —pnpm exec vitest run src/lib/batch.test.ts.App.svelteadapter over the #6 engine —pnpm check+pnpm test.batch.test.tswith the real engine (createCadesFixtures→loadSignerSession→signCadesDetached) andopenssl cms -verifyon every output; failure path = a certificate ofthe container that has no private key (a real engine rejection, no fabricated error).
verify-batch-zip.mjs—node web/scripts/verify-batch-zip.mjs(exit 0).build/served over HTTP, real PKCS#12 generated withopenssl, threedocuments dropped, certificates loaded, batch run → live
signing→signedstatuses,downloaded ZIP extracted and every
.csigverified withopenssl cms -verify -cades.test -d decompiled;find decompiled -name '*.java' | grep -q .;git diff --check;pnpm test;pnpm check;pnpm build;pnpm verify:zip.Open questions (assumptions taken — no human to ask)
(
JSONBatchInfo,singlesigns[]withid/datareference/format/suboperation) and theresult envelope (
JSONBatchInfoParser.buildResult,signs[]withid/result/description).Assumption: emit the definition array with results written back into each entry, exactly like
JSONBatchInfo.updateResults, plus the issue'ssha256/timestamp/output name as extra fields.CompressionStreamis browser-only and no dependency may be added;a stored ZIP is a valid ZIP (
unzip -taccepts it).ponytail:comment marks the upgrade path.resultvalues: only the client-reachableNOT_STARTED/DONE_AND_SAVED/ERROR_PREareemitted; the rest of
BatchDataResult.Resultis listed in a comment as the mirror source.signbatch.algorithm: required byBatchSigner.java:205; derived from the certificate'sWebCrypto parameters by
signingAlgorithmName()(e.g.SHA256withRSA).Risk and boring fallback
openssl/unzipmissing on the reviewer's machinezlib.crc32beforeAll)Session 8 addendum (revised 2026-10-14)
The branch arrived at
62dc44ewith every task above already implemented and committed. There isnothing left to build, so this session's work is the plan's own verification column run fresh:
62dc44e—test -d decompiled,find decompiled -name '*.java' | grep -q .,git diff --check,pnpm test,pnpm check,pnpm build,pnpm verify:zip.web/build/over HTTP, headless Chromium via the harness: drop 3 files, load the container,click Firmar, record the
data-statuspaint trace, download the ZIP for real, then verify itoutside the browser (
unzip -t,sha256sumvsmanifest.json,openssl cms -verify -cadesper output).
Forge comments could not be posted from sessions 4–7 (empty
BULLET_TOKEN, private repo → 404);BULLET_BASICauthenticates (GET /api/v1/user200,id1EduarD3V), so claim/plan/done landthis session.
DONE — HEAD
ee218e6(session 8). Branchissue/9-use-case-batch-sign-queue-mult, worktree clean, nothing pushed,Refs #9.Commits:
a0b98bdqueue+manifest+ZIP writer,efb9352e2e tests + ZIP cross-check,a948238stack on #5/#6,edda9ebverified against real CAdES engine,62dc44eBatchQueue unsubscribe,ee218e6(this session) abort a run whose document list was replaced mid-flight + test.Gates (all exit 0 at
ee218e6):test -d decompiled— 0find decompiled -name "*.java" | grep -q .— 0 (11 487 files)git diff --check— 0cd web && pnpm test— 0 (4 files, 28 tests)cd web && pnpm check— 0 (377 files, 0 errors 0 warnings)cd web && pnpm build— 0cd web && pnpm verify:zip— 0 (unzip -t clean, digests match manifest)Evidence this session: fresh PKCS#12 + fresh documents in headless Chromium — 3 files signed one at a time (never two
signingrows, Firmar disabled throughout), ZIP downloaded from the browser and verified outside it (unzip -t, sha256sum == manifest digests,openssl cms -verify -cadesOK for all three). Defect found and fixed: dropping a file mid-run let the abandoned run record results on the new list (positional ids); now gated by a generation counter — unit test proven red without the fix, and confirmed in the browser (4 rows staypending). Manifest fields mirrorJSONBatchInfo.java(singlesigns[]: id/datareference/format/suboperation + result/description + sha256/timestamp/output).bullet: coder session died — relaunched from committed state (branch
issue/9-use-case-batch-sign-queue-mult).bullet: implementation finished (DONE — HEAD
ee218e6(session 8). Branchissue/9-use-case-batch-sign-queue-mult, worktree clean, nothing pushed,Refs #9.) — moving to review.bullet: reviewer launched (model
9router/reviewer, independent of coder).REVIEW: CLEAN — commit
ee218e6: all 4 acceptance criteria met (sequential queue batch.ts:162-193; resume batch.test.ts:168; manifest fields match JSONBatchInfo.java; 3-file e2e batch.test.ts:121 + App.test.ts:132); gates green: pnpm test 28/28, pnpm check 0/0, pnpm build, pnpm verify:zip, git diff --check, decompiled gates; no tests skipped or weakened; findings: nonebullet: review CLEAN — ready to publish.
bullet: merge conflicts with
bullet-develop— conflict-solver agent owns the worktree until it pushes.bullet: PR #21 open →
bullet-develop(auto-merge follows).bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into
bullet-develop; PR auto-merges next tick.bullet: merge conflicts with
bullet-develop— conflict-solver agent owns the worktree until it pushes.bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into
bullet-develop; PR auto-merges next tick.Claimed — branch
issue/9-use-case-batch-sign-queue-mult. Doing: replay #9 batch-queue branch onto bullet-develop (HEAD0bbd2bf), resolve conflicts against later #7/#8/#10/#3 web work, run gates.Claimed — branch
bullet-develop. Doing: merge origin/main (the already-landed PR #20 merge, tree-identical to bullet-develop) into bullet-develop, run gates, report.INTEGRATED: #9 merged into bullet-develop (conflicts resolved: App.svelte/App.test.ts/i18n.ts/sign.ts/FileDrop.svelte/README.md rebuilt so the batch queue is the sign flow while #7 XAdES and #8 verify mode keep working) — merge
0e0bb1e, gates exit 0, 86/86 vitest, svelte-check clean, ZIP+openssl+xmlsec1 cross-checks pass.RECONCILED: trunk work merged into bullet-develop (conflicts resolved: none textual — origin/main
159a710is a merge of0bbd2bf, so the trunk merge was content-free; the branch now carries the reviewed #9 batch work from the peer conflict-solver merge0e0bb1e, my merge commit442624f, gates green) — Refs #9bullet: merged into
bullet-develop— integration gates green.bullet: PR #21 closed — work already merged into
bullet-develop.