Skip to content

Commit 1612572

Browse files
Jonathan D.A. Jewellclaude
andcommitted
feat: production hardening — benchmarks, workflows, Containerfile, security standard
Add criterion benchmarks (7 total: IPP parsing/response/hashing, encrypt/decrypt roundtrip, integrity hashing at 4 sizes, audit recording, perspective correction). Add 3 new GitHub Actions workflows: security.yml (cargo-audit, strict clippy, panic surface check), release.yml (build + GitHub Release on tag), bench.yml (run benchmarks on push to main). Add multi-stage Containerfile using chainguard wolfi-base with non-root runtime, health check, and OCI labels. Update Trustfile.hs to implement 7-step hyperpolymath security standard verification (ABI proofs, banned patterns, audit integrity, encryption safety, post-quantum readiness, hash compliance, policy hash). Documents migration path from current crypto (SHA-256, Ed25519, age/X25519) to target standard (SHAKE3-512, Ed448+Dilithium5, Kyber-1024, XChaCha20-Poly1305, Argon2id). Fix CodeQL workflow (actions language, not javascript-typescript). Fix fallback init (AppServices::fallback with in-memory databases). Add crates.io metadata, CHANGELOG.md, security architecture documentation. Update all stats: 46 files, 10749 lines, 68 tests, 7 benchmarks, 21 workflows. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4397c3f commit 1612572

23 files changed

Lines changed: 1359 additions & 163 deletions

File tree

.github/workflows/bench.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Presswerk — Run workspace benchmarks (informational)
3+
4+
name: Benchmarks
5+
6+
on:
7+
push:
8+
branches: [main]
9+
10+
permissions: read-all
11+
12+
jobs:
13+
bench:
14+
name: Run Benchmarks
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
18+
- uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
19+
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
20+
21+
- name: Install system dependencies
22+
run: |
23+
sudo apt-get update
24+
sudo apt-get install -y libxdo-dev libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev
25+
26+
- name: Run benchmarks
27+
run: cargo bench --workspace

.github/workflows/codeql.yml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Presswerk — CodeQL workflow analysis (Rust not supported; scans Actions only)
23
name: CodeQL Security Analysis
34

45
on:
56
push:
6-
branches: [main, master]
7+
branches: [main]
78
pull_request:
8-
branches: [main, master]
9+
branches: [main]
910
schedule:
1011
- cron: '0 6 * * 1'
1112

@@ -21,20 +22,20 @@ jobs:
2122
fail-fast: false
2223
matrix:
2324
include:
24-
- language: javascript-typescript
25+
- language: actions
2526
build-mode: none
2627

2728
steps:
2829
- name: Checkout
29-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
30+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
3031

3132
- name: Initialize CodeQL
32-
uses: github/codeql-action/init@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v3.28.1
33+
uses: github/codeql-action/init@6624720a57d4c312633c7b953db2f2da5bcb4c3a # v3
3334
with:
3435
languages: ${{ matrix.language }}
3536
build-mode: ${{ matrix.build-mode }}
3637

3738
- name: Perform CodeQL Analysis
38-
uses: github/codeql-action/analyze@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v3.28.1
39+
uses: github/codeql-action/analyze@6624720a57d4c312633c7b953db2f2da5bcb4c3a # v3
3940
with:
4041
category: "/language:${{ matrix.language }}"

.github/workflows/release.yml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Presswerk — Build release binary and create GitHub Release on tag push
3+
4+
name: Release
5+
6+
on:
7+
push:
8+
tags:
9+
- "v*"
10+
11+
permissions: write-all
12+
13+
jobs:
14+
build-linux:
15+
name: Build (x86_64-unknown-linux-gnu)
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
19+
- uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
20+
with:
21+
targets: x86_64-unknown-linux-gnu
22+
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
23+
24+
- name: Install system dependencies
25+
run: |
26+
sudo apt-get update
27+
sudo apt-get install -y libxdo-dev libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev
28+
29+
- name: Build release binary
30+
run: cargo build --release --target x86_64-unknown-linux-gnu -p presswerk-app
31+
32+
- name: Package binary
33+
run: |
34+
mkdir -p dist
35+
cp target/x86_64-unknown-linux-gnu/release/presswerk-app dist/presswerk-linux-x86_64
36+
chmod +x dist/presswerk-linux-x86_64
37+
38+
- name: Upload artifact
39+
uses: actions/upload-artifact@v4
40+
with:
41+
name: presswerk-linux-x86_64
42+
path: dist/presswerk-linux-x86_64
43+
retention-days: 7
44+
45+
create-release:
46+
name: Create GitHub Release
47+
runs-on: ubuntu-latest
48+
needs: build-linux
49+
steps:
50+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
51+
52+
- name: Download artifacts
53+
uses: actions/download-artifact@v4
54+
with:
55+
name: presswerk-linux-x86_64
56+
path: dist/
57+
58+
- name: Create release
59+
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2
60+
with:
61+
generate_release_notes: true
62+
files: |
63+
dist/presswerk-linux-x86_64
64+
env:
65+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/security.yml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Presswerk — Security scanning (cargo-audit, strict clippy, unwrap detection)
3+
4+
name: Security Scan
5+
6+
on:
7+
push:
8+
branches: [main]
9+
schedule:
10+
- cron: "0 6 * * 1"
11+
12+
permissions: read-all
13+
14+
jobs:
15+
cargo-audit:
16+
name: Cargo Audit
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
20+
- uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
21+
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
22+
23+
- name: Install cargo-audit
24+
run: cargo install cargo-audit --locked
25+
26+
- name: Run cargo audit
27+
run: cargo audit
28+
29+
clippy-strict:
30+
name: Clippy (Strict / Library Crates)
31+
runs-on: ubuntu-latest
32+
steps:
33+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
34+
- uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
35+
with:
36+
components: clippy
37+
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
38+
39+
- name: Install system dependencies
40+
run: |
41+
sudo apt-get update
42+
sudo apt-get install -y libxdo-dev libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev
43+
44+
- name: Clippy pedantic (library crates)
45+
run: |
46+
cargo clippy \
47+
-p presswerk-core \
48+
-p presswerk-security \
49+
-p presswerk-document \
50+
-p presswerk-print \
51+
-- -D warnings -W clippy::pedantic
52+
53+
panic-check:
54+
name: Panic Surface Check (Informational)
55+
runs-on: ubuntu-latest
56+
steps:
57+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
58+
59+
- name: Count unwrap/expect usage outside tests
60+
run: |
61+
echo "=== Scanning for unwrap()/expect() in crates/ ==="
62+
echo "(Excluding #[cfg(test)] and mod tests blocks)"
63+
echo ""
64+
count=0
65+
while IFS= read -r file; do
66+
results=$(awk '
67+
/^[[:space:]]*#\[cfg\(test\)\]/ { skip=1; next }
68+
/^[[:space:]]*mod tests/ { skip=1; brace=0; next }
69+
skip && /{/ { brace++ }
70+
skip && /}/ { brace--; if (brace<=0) skip=0; next }
71+
skip { next }
72+
/\.unwrap\(\)|\.expect\(/ { print FILENAME ":" NR ": " $0 }
73+
' "$file")
74+
if [ -n "$results" ]; then
75+
echo "$results"
76+
file_count=$(echo "$results" | wc -l)
77+
count=$((count + file_count))
78+
fi
79+
done < <(find crates/ -name '*.rs' -type f)
80+
echo ""
81+
echo "=== Total unwrap()/expect() calls outside test code: $count ==="
82+
if [ "$count" -gt 0 ]; then
83+
echo "::notice::Found $count unwrap()/expect() calls outside test code."
84+
else
85+
echo "::notice::No unwrap()/expect() calls found outside test code."
86+
fi
87+
exit 0

.machine_readable/STATE.scm

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,50 @@
11
;; SPDX-License-Identifier: PMPL-1.0-or-later
2-
(state (metadata (version "0.2.0") (last-updated "2026-02-14") (status active))
2+
(state (metadata (version "0.3.0") (last-updated "2026-02-14") (status active))
33
(project-context
44
(name "presswerk")
55
(purpose "High-assurance local print router and server for iOS/Android")
6-
(completion-percentage 65))
6+
(completion-percentage 75))
77
(components
8-
(component "presswerk-core" (status "complete") (description "Shared types, errors, config — 244-line types, 70-line errors"))
9-
(component "presswerk-security" (status "complete") (description "age encryption, SHA-256 integrity, Ed25519 certs, SQLite audit trail — 14 tests"))
10-
(component "presswerk-document" (status "complete") (description "PDF read/merge/split/rotate, image processing, scan enhancement, OCR — 7 tests"))
11-
(component "presswerk-print" (status "complete") (description "Full IPP/1.1 server (1936 lines), IPP client, mDNS discovery, SQLite job queue — 40 tests"))
8+
(component "presswerk-core" (status "complete") (description "Shared types, errors, config — 248-line types, 70-line errors"))
9+
(component "presswerk-security" (status "complete") (description "age encryption, SHA-256 integrity, Ed25519 certs, SQLite audit trail — 14 tests, 3 benchmarks"))
10+
(component "presswerk-document" (status "complete") (description "PDF read/merge/split/rotate, image processing, scan enhancement with perspective correction, OCR — 7 tests, 1 benchmark"))
11+
(component "presswerk-print" (status "complete") (description "Full IPP/1.1 server (2170 lines), IPP client, mDNS discovery, SQLite job queue — 47 tests, 3 benchmarks"))
1212
(component "presswerk-bridge" (status "unverified") (description "iOS objc2 (894 lines) + Android JNI (973 lines) — detailed but untested on device"))
13-
(component "presswerk-app" (status "functional") (description "Dioxus UI with 10 pages, routing, AppServices layer, settings"))
13+
(component "presswerk-app" (status "functional") (description "Dioxus UI with 10 pages, routing, AppServices layer with fallback mode, settings"))
1414
(component "abi-proofs" (status "complete") (description "5 Idris2 files: Types, Protocol, Encryption, Layout, Bridge — no Admitted"))
15-
(component "ffi-zig" (status "complete") (description "C-compatible FFI with 5 tests — lifecycle, transitions, hash, version")))
15+
(component "ffi-zig" (status "complete") (description "C-compatible FFI with 5 tests — lifecycle, transitions, hash, version"))
16+
(component "benchmarks" (status "complete") (description "Criterion benchmarks for security (3), print (3), document (1) — 7 total"))
17+
(component "ci-workflows" (status "complete") (description "21 GitHub Actions workflows including security.yml, release.yml, bench.yml"))
18+
(component "containerfile" (status "complete") (description "Multi-stage chainguard-based Containerfile for headless print server"))
19+
(component "trustfile" (status "complete") (description "Haskell-based security verification — 7-step hyperpolymath standard")))
1620
(metrics
17-
(rust-files 43)
18-
(rust-lines 10219)
21+
(rust-files 46)
22+
(rust-lines 10749)
1923
(idris2-files 5)
2024
(zig-files 3)
21-
(unit-tests 61)
25+
(unit-tests 68)
26+
(benchmarks 7)
27+
(workflows 21)
2228
(clippy-warnings 0)
29+
(cargo-audit-vulnerabilities 0)
2330
(panic-attack-critical 0)
2431
(panic-attack-high 4)
2532
(panic-attack-medium 5))
2633
(current-position
27-
(phase "Phase 7Production Hardening")
28-
(milestone "Core implementation complete, formal verification done, doc storage implemented")
34+
(phase "Phase 8Release and Packaging")
35+
(milestone "Production hardening complete, benchmarks added, CI/security workflows deployed")
2936
(next-actions
30-
("Test iOS bridge on device/simulator (requires macOS + Xcode)"
37+
("Create v0.1.0 release tag and GitHub release"
38+
"Push to GitLab mirror"
39+
"Test iOS bridge on device/simulator (requires macOS + Xcode)"
3140
"Test Android bridge on device/emulator (requires NDK)"
32-
"Add TLS to IPP server (rustls cert already generated)"
33-
"Add rate limiting to IPP server"
41+
"Migrate to post-quantum crypto standard (Argon2id, SHAKE3-512, Kyber-1024)"
3442
"Apple Developer Team ID for iOS signing")))
3543
(blockers-and-issues
3644
(blocker "iOS bridge never compiled on target — need macOS + Xcode")
3745
(blocker "Android bridge never compiled on target — need NDK")
3846
(blocker "Dioxus.toml team_id empty — need Apple Developer account")
3947
(note "Desktop dev mode works via stub bridge")
40-
(note "All 4 panic-attack High findings are unavoidable FFI unsafe — covered by Bridge.idr proofs")))
48+
(note "All 4 panic-attack High findings are unavoidable FFI unsafe — covered by Bridge.idr proofs")
49+
(note "14 cargo audit warnings are unmaintained GTK3 transitive deps from dioxus-desktop — not actionable")
50+
(note "Crypto migration: SHA-256 -> SHAKE3-512, Ed25519 -> Ed448+Dilithium5, X25519 -> Kyber-1024")))

0-AI-MANIFEST.a2ml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,23 @@ Generated C headers in `generated/abi/`.
6363
## SESSION STARTUP CHECKLIST
6464

6565
1. Read THIS file (0-AI-MANIFEST.a2ml) first
66-
2. Read `.machine_readable/STATE.scm` for current status (65% complete)
67-
3. Run `cargo test --workspace` to verify state (61 tests expected)
66+
2. Read `.machine_readable/STATE.scm` for current status (75% complete)
67+
3. Run `cargo test -p presswerk-core -p presswerk-security -p presswerk-document -p presswerk-print` to verify state (68 tests expected)
6868
4. Check for blockers in STATE.scm
6969

7070
## PROJECT STATUS
7171

72-
- **Completion:** 65%
73-
- **Stats:** 43 Rust files, 10,219 lines, 5 Idris2 ABI files, 3 Zig FFI files
74-
- **Tests:** 61 unit tests (40 print + 14 security + 7 document), 0 failures
72+
- **Version:** 0.1.0
73+
- **Completion:** 75%
74+
- **Stats:** 46 Rust files, 10,749 lines, 5 Idris2 ABI files, 3 Zig FFI files
75+
- **Tests:** 68 unit tests (47 print + 14 security + 7 document), 0 failures
76+
- **Benchmarks:** 7 criterion benchmarks (3 security + 3 print + 1 document)
77+
- **Workflows:** 21 GitHub Actions (CI, security scan, release, benchmarks, CodeQL, Scorecard, etc.)
7578
- **Clippy:** 0 warnings
79+
- **Audit:** 0 vulnerabilities (14 warnings — unmaintained GTK3 transitive deps)
7680
- **Security:** panic-attack 0 critical, 4 high (FFI — covered by Bridge.idr)
81+
- **Container:** Containerfile (chainguard wolfi-base, multi-stage, non-root)
82+
- **Trustfile:** 7-step verification (ABI, banned patterns, audit, encryption, PQ readiness, hash, policy)
7783
- **Remotes:** GitHub + GitLab (hyperpolymath/presswerk)
7884

7985
## META

CHANGELOG.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [0.1.0] - 2026-02-14
9+
10+
### Added
11+
12+
- **presswerk-core**: Shared types (14 public types), error handling, app config
13+
- **presswerk-security**: age (X25519) encrypted storage, SHA-256 document integrity, Ed25519 TLS certificates, append-only SQLite audit trail
14+
- **presswerk-document**: PDF read/merge/split/rotate/crop (lopdf + printpdf), image processing (resize, rotate, crop, grayscale, brightness), scanning pipeline with Canny edge detection, Hough line detection, perspective correction, binarisation, OCR via ocrs (pure Rust)
15+
- **presswerk-print**: Full IPP/1.1 server (2,170 lines, RFC 8010/8011 compliant), IPP client (Print-Job, Get-Printer-Attributes, Get-Jobs, Cancel-Job), mDNS/DNS-SD printer discovery, persistent SQLite job queue
16+
- **presswerk-bridge**: iOS native bridges (objc2 — UIPrintInteractionController, UIImagePickerController, UIDocumentPickerViewController, Security.framework Keychain, UIActivityViewController), Android native bridges (JNI — PrintManager, Intent ACTION_IMAGE_CAPTURE, Storage Access Framework, Android Keystore, Intent ACTION_SEND)
17+
- **presswerk-app**: Dioxus 0.7 UI with 10 pages (Home, Print, Scan, Edit, TextEditor, Server, Jobs, Audit, Settings), bottom tab navigation, AppServices layer with in-memory fallback mode
18+
- **Idris2 ABI proofs**: 5 proof files (Types, Protocol, Encryption, Layout, Bridge) — 0 Admitted, 0 believe_me
19+
- **Zig FFI**: C-compatible exports (8 functions, 5 tests)
20+
- **Benchmarks**: 7 criterion benchmarks (IPP parsing, response building, content hashing, encrypt/decrypt roundtrip, integrity hashing at 4 sizes, audit recording, perspective correction)
21+
- **CI/CD**: 21 GitHub Actions workflows (CI, security scan, release, benchmarks, CodeQL, OpenSSF Scorecard, hypatia scan, mirror, quality, secret scanning)
22+
- **Containerfile**: Multi-stage chainguard (wolfi-base) build, non-root runtime, health check
23+
- **Trustfile**: 7-step security verification (ABI proofs, banned patterns, audit integrity, encryption safety, PQ readiness, hash compliance, policy hash)
24+
- **Content-addressed document storage**: Deduplication via SHA-256 hash filenames
25+
26+
### Security
27+
28+
- 0 critical vulnerabilities (panic-attack scan)
29+
- 0 dependency vulnerabilities (cargo audit)
30+
- All `unsafe` blocks documented with `// SAFETY:` comments referencing Idris2 proofs
31+
- No banned patterns: 0 `Admitted`, 0 `believe_me`, 0 `transmute`, 0 `unsafePerformIO`
32+
- Append-only audit trail (no DELETE/UPDATE)
33+
- Encryption key never persisted to disk
34+
35+
[0.1.0]: https://github.com/hyperpolymath/presswerk/releases/tag/v0.1.0

0 commit comments

Comments
 (0)