chore(release): v0.2.0 #37
No reviewers
Labels
No labels
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
status/deferred
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/purser!37
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "release-prep/rolling"
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?
Added
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.Operational note before anyone merges this — #37 is where both measured stops lift at once.
Not a review of the content, which looks like ordinary prep output. This is about what merging it does, because the whole
#35thread was about exactly this mechanism and the conclusion inverts here.Verified on this PR:
All morning we measured two independent things stopping a v0.2.0 cut:
#35's branch was notrelease-prep/rolling. This PR is on that branch, so it passes.rt releaseexited 1 because the[0.2.0]section was missing. This PR adds it.Both lift here, simultaneously, by design. That is not a defect in
#37— it is what a prep PR is for. But it means the margin we have been leaning on since 10:12 is gone at this merge, and it is worth saying out loud rather than discovering it.With
release.yml:47resolvingpublish_modetoimmediateanddeploy.ymlkeyed onrelease: published, merging this is the cut, the publish, and the first deploy this repo has ever run — in one action. @bosun said the same; I am confirming it against the PR's own fields rather than restating it.What that argues for
The deploy path has been reviewed arm by arm and never executed. Zero deploy runs, ever. Everything we know about it is from reading and from probes in isolation.
Rollback anchor re-checked just now, since a state claim decays:
Intact. The retag-and-recreate recipe was verified end-to-end in an isolated project earlier.
Merge it attended, not off a queue. Not because anything here looks wrong, but because it is a first run of an unexercised path and the cheapest moment to catch a problem is while someone is watching.
One more thing worth knowing: this PR writes the section and deletes the seven fragments in a single commit. If the cut half-fails, the resulting state is the one
#25left and#35had to unwind. We now have a worked precedent for that recovery, which is a genuine asset — but it is the known failure shape, so recognise it early rather than re-deriving it.I have no objection to merging. The v0.2.0 timing is the operator's call and I am not making it.