-
Release v0.2.0
Stablereleased this
2026-08-06 11:50:19 +02:00 | 21 commits to main since this releaseAdded
-
store: expired certificates' bundles are purged, so a stolen backup carries less (#3)
A sweep runs at startup and hourly, clearing the stored
.p12ciphertext of any certificate past itsnot_after. The audit row stays; only the key material goes. Keyed onnot_afterand never onrevoked_at— a revoked-but-unexpired record keeps its bundle, because the 403 refusal path reads it. A download resolving to a purged record now returns 410 rather than a zero-byte file. -
deploy: pass VERSION to the build and assert the deployed binary reports it
-
deploy: probe the #5 regression surface, and make the probe parser field-safe
-
deploy: deploy purser from CI on release cuts
Changed
None.
Fixed
-
version: inject release tag via Dockerfile
VERSIONbuild-arg (#16)docker compose build --build-arg VERSION=v0.1.0now stamps the binary; without the arg the build falls back to the VCS commit hash or"dev". The ldflags path is-X git.frankenbit.de/frankenbit/purser/internal/version.Tag. -
changelog: split three sentences over the 30-word density ceiling
-
deploy: arm 5 must survive a version-less page, and the disclosure contradicted it
-
docs: 120 bits bounds the password search, not the bundle's strength
-
docs: legacy-des does not use PBKDF2 — and the error was in three places
-
deploy: arm 4 asserts the exact 404 contract, not merely "not a redirect"
-
deploy: wait for health before probing — the inspect raced the healthcheck
Removed
None.
Deprecated
None.
Upgrade
None.
Internal
-
purser: every post-sign failure path is now proven to revoke, not just inspected (#12)
The existing
TestAbandon_*tests calledabandon()directly, so removing its call from any exit inIssue()left them green while a live certificate leaked. FourIssue()-level tests now cover the drift, password, packaging and store exits, each mutation-verified to redden only for its own branch. No behaviour change. -
purser:
PURSER_EMBED_CA_ROOTis now verified against the bundle it produces (#13)The
loadCARoottests check the loader in isolation and would all pass withService.CARootassigned nowhere — the original defect. A new test decodes the issued.p12and asserts the root is present with the flag set and absent without it. No behaviour change. -
purser: the profile gate's key baseline is pinned to the measured RSA-3072, not derived from config (#2)
expectedProfile()used to take the key expectation fromPURSER_KEY_TYPE, so setting ECDSA made ECDSA the expectation and the gate fell silent at the one moment it exists to speak. A setting proves intent, not that the device accepts it.PURSER_ALLOW_PROFILE_DRIFTremains the named path to change it deliberately and measure. The override and the conforming happy path are now tested atIssue(); both were untested. -
docs: the backup-alone claim now states both legs it rests on (#3)
The claim lived in
internal/storewhile the entropy supporting it was stated ininternal/purser, so a reader had to cross packages to learn what it depended on. It rests on a conjunction. The password contributes 120 bits against a password search; the encryption is the other, equally load-bearing leg. Under the deployedlegacy-desthe 3DES cipher binds first, at ~112 bits. Also records why the PKCS#12 iteration count is deliberately not raised. -
docs: the
168hcertificate lifetime now carries its reasoning (#4)The value was chosen and proven. The configuration table still described it only as "how long an issued certificate is valid". That is the unexplained-number state this tracker exists to prevent, with a new number in it.
docs/operations.mdnow states the deployed value, the8760hprovisioner ceiling, and the reason not to reach for it. ocserv consults no CRL, soNotAfteris the only mechanism that ends access.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-