Skip to content

Commit 141e46c

Browse files
committed
Sun Dec 14 21:28:57 PST 2025
1 parent e618fb0 commit 141e46c

5 files changed

Lines changed: 45 additions & 64 deletions

File tree

.envrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ has nix
55
watch_dir nix
66
watch_file flake.nix
77
watch_file flake.lock
8-
use flake .
8+
use flake . -L --accept-flake-config

.github/workflows/ci.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ jobs:
1010
build:
1111
name: Build (${{ matrix.name }})
1212
runs-on: ${{ matrix.runs_on }}
13+
permissions:
14+
id-token: write
15+
contents: read
16+
attestations: write
1317
strategy:
1418
fail-fast: false
1519
matrix:
@@ -36,7 +40,6 @@ jobs:
3640
with:
3741
name: pdf-sign
3842
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
39-
skipPush: ${{ github.event_name == 'pull_request' }}
4043

4144
- name: Build (flake)
4245
run: |
@@ -51,6 +54,11 @@ jobs:
5154
mkdir -p dist
5255
cp -L result/bin/pdf-sign "dist/pdf-sign-${{ runner.os }}-$(uname -m)"
5356
57+
- name: Generate artifact attestation
58+
uses: actions/attest-build-provenance@v3
59+
with:
60+
subject-path: dist/*
61+
5462
- name: Upload artifact
5563
uses: actions/upload-artifact@v6
5664
with:
@@ -86,7 +94,6 @@ jobs:
8694
with:
8795
name: pdf-sign
8896
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
89-
skipPush: ${{ github.event_name == 'pull_request' }}
9097

9198
- name: Build dev shell
9299
run: |

README.md

Lines changed: 9 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,18 @@ Many "enterprise PDF signing" solutions require a full **CMS/PKCS#7** / **X.509
1414

1515
* **Two signing backends**: Choose between traditional GPG (with hardware key support) or modern Sigstore (keyless OIDC).
1616
* **Preserves PDF integrity**: Original PDF content unchanged; signatures appended after `%%EOF`.
17-
* **Multi-signer workflow**: Supports multiple signatures (GPG + Sigstore) on the same document.
17+
* **Multi-signer workflow**: Supports multiple signatures (GPG + Sigstore) on the same document, and/or multi-party signing.
1818
* **Privacy-preserving**: No extra PII embedded; library never logs sensitive data.
19-
* **Portable architecture**: Clean core library (WASM-ready) with pluggable backends.
2019

2120
## Quickstart
2221

22+
### Install with Nix
23+
24+
```bash
25+
nix profile install github:0x77dev/pdf-sign#pdf-sign
26+
pdf-sign --help
27+
```
28+
2329
### Install with Cargo
2430

2531
```bash
@@ -35,13 +41,6 @@ pdf-sign sign --backend sigstore document.pdf
3541
pdf-sign verify document_signed.pdf
3642
```
3743

38-
### Install with Nix
39-
40-
```bash
41-
nix profile install github:0x77dev/pdf-sign#pdf-sign
42-
pdf-sign --help
43-
```
44-
4544
### Build from Source
4645

4746
```bash
@@ -211,7 +210,6 @@ pdf-sign apply-response document.pdf \
211210

212211
* **Portable core**: PDF splitting, suffix parsing, digest abstraction (no CLI/UI deps).
213212
* **Pluggable backends**: Clean separation between GPG and Sigstore signing logic.
214-
* **WASM-ready**: Core library and backends compile to WebAssembly.
215213
* **Hash agility**: SHA-512 default with SRI-style encoding (`sha512-<base64>`).
216214
* **Versioned format**: Sigstore blocks use bilrost (efficient binary) with version tagging.
217215
* **Structured tracing**: Full `tracing` instrumentation (never logs sensitive data).
@@ -280,25 +278,6 @@ Versioned bilrost-encoded blocks with digest binding:
280278
* Network access (Fulcio, Rekor, OIDC provider)
281279
* No keys/certs required
282280

283-
## Workspace Structure
284-
285-
```text
286-
crates/
287-
├── core/ # Portable library (PDF, suffix, digest) - WASM-compatible
288-
├── gpg/ # OpenPGP backend (sequoia) - WASM-compatible
289-
├── sigstore/ # Sigstore keyless backend - WASM-compatible
290-
├── wasm/ # WebAssembly bindings with TypeScript definitions
291-
└── cli/ # CLI with UI/JSON/tracing setup - Native only
292-
```
293-
294-
Modular design enables:
295-
296-
* Backend-agnostic PDF processing
297-
* Full WASM support (core + gpg + sigstore)
298-
* Clean testing boundaries
299-
* Structured tracing without data leakage
300-
* TypeScript-first browser integration
301-
302281
## Environment Variables
303282

304283
* `GNUPGHOME`: GPG keybox location (default: `~/.gnupg`)
@@ -382,37 +361,6 @@ pdf-sign apply-response sensitive.pdf \
382361
pdf-sign verify sensitive_signed.pdf
383362
```
384363

385-
### WASM in browser
386-
387-
```bash
388-
# Build WASM package with Nix
389-
nix develop
390-
cd crates/wasm
391-
wasm-pack build --target web
392-
393-
# Copy pkg/ to your web project
394-
cp -r pkg /path/to/your/web/project/
395-
```
396-
397-
```javascript
398-
import init, { prepare_challenge, apply_response, verify_gpg } from './pkg/pdf_sign_wasm.js';
399-
400-
await init();
401-
402-
// Client-side GPG verification
403-
const pdfFile = await fetch('document_signed.pdf');
404-
const pdfBytes = new Uint8Array(await pdfFile.arrayBuffer());
405-
const result = verify_gpg(pdfBytes);
406-
407-
if (result.valid) {
408-
console.log('Valid signatures:');
409-
result.gpg_signatures.forEach(sig => {
410-
console.log(` - ${sig.fingerprint}`);
411-
sig.uids.forEach(uid => console.log(` ${uid}`));
412-
});
413-
}
414-
```
415-
416364
## License
417365

418-
GPL-3.0-only
366+
GPL-3.0-only – See [`LICENSE`](./LICENSE).

flake.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
nixConfig = {
55
extra-substituters = [
66
"https://pdf-sign.cachix.org"
7+
"https://nix-community.cachix.org"
78
];
89
extra-trusted-public-keys = [
910
"pdf-sign.cachix.org-1:RjOq/uF6ksxVZsLfI9+SW4Nkhcc63+klWAoAtkZRF2U="
11+
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
1012
];
1113
};
1214

nix/package.nix

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,30 @@ rec {
5454
mainProgram = "pdf-sign";
5555
platforms = platforms.unix;
5656
};
57+
58+
passthru.image = image;
5759
}
5860
);
61+
62+
image = pkgs.dockerTools.buildLayeredImage {
63+
name = "ghcr.io/0x77dev/pdf-sign";
64+
tag = "latest";
65+
66+
contents = [ pdfSign ];
67+
68+
config = {
69+
Cmd = [ "${lib.getExe pdfSign}" ];
70+
WorkingDir = "/work";
71+
Env = [
72+
"GNUPGHOME=/gnupg"
73+
];
74+
ExposedPorts = {
75+
"8080/tcp" = { };
76+
};
77+
Volumes = {
78+
"/gnupg" = { };
79+
"/work" = { };
80+
};
81+
};
82+
};
5983
}

0 commit comments

Comments
 (0)