Skip to content

Release 1.0.0#13

Merged
systemslibrarian merged 3 commits into
mainfrom
release/1.0.0
Jul 1, 2026
Merged

Release 1.0.0#13
systemslibrarian merged 3 commits into
mainfrom
release/1.0.0

Conversation

@systemslibrarian

Copy link
Copy Markdown
Owner

First stable release. Brings the library from 0.1.0 to a production-ready 1.0 with a frozen, authenticated envelope, a real key-rotation story, a locked public API surface, and expanded security tests. Commits to SemVer (API + format stability) for the 1.x line.

Highlights

Crypto / security

  • Hybrid envelope format v2: the ML-KEM encapsulation block is folded into the AES-GCM associated data (HPKE-style; no unauthenticated bytes). Reads legacy v1 hybrid envelopes; AES envelopes unchanged (still v1).
  • Fail-fast validation of the default scheme at protector construction — misconfiguration (e.g. ML-KEM default on an unsupported host) throws at startup, not first write.
  • Supply chain: pinned the patched SQLite native bundle (SQLitePCLRaw 3.x), clearing advisory GHSA-2m69-gcr7-jv3q (test/sample-only; not shipped).

API / DX

  • IsEncrypted rejects unsupported property types with a clear, property-named error.
  • In-place, thread-safe key rotation on the in-memory rings (AddKey/SetActiveKey/RemoveKey) — required because EF caches the model (and the captured protector) per context type, so swapping the ring cannot rotate.
  • Re-encryption sweep ReEncryptAsync<TEntity, TKey>() + MarkEncryptedPropertiesModified, which force EF to re-run the converter (a plain SaveChanges does not). The sweep snapshots primary keys and batches by key membership (not offset paging), so it is safe to run online, and requires a dedicated context so it never touches your app's tracked graph.
  • Locked public API surface via PublicApiAnalyzer + PublicAPI.Shipped.txt baseline.

Sample

  • Fixed a latent bug where the KEK was disposed inside the config lambda, breaking the sample on any ML-KEM-capable machine.

Docs / versioning

  • README: Always Encrypted / TDE comparison table, "not ASP.NET Data Protection" note, rewritten rotation guide, 1.x API + format stability commitment.
  • Updated KNOWN-GAPS, threat model, migration guide, CHANGELOG; bumped to 1.0.0.

Testing

  • Test suite expanded 35 → 58; passes on net8.0 and net10.0 (Release) locally; net9.0 via CI. Solution builds clean with warnings-as-errors; sample runs end-to-end writing v2 post-quantum envelopes; 1.0.0 package + symbols pack successfully.

Notes for release

  • Compatibility: 0.1.0 cannot read the v2 hybrid envelopes 1.0 writes — upgrade all nodes before writing post-quantum values (AES envelopes are unaffected).
  • After merge: tag v1.0.0 to trigger the Publish workflow (requires a valid NUGET_API_KEY secret).

🤖 Generated with Claude Code

systemslibrarian and others added 3 commits June 30, 2026 20:30
Bring the library to a stable 1.0 release.

Crypto/security:
- Hybrid envelope format v2: fold the ML-KEM encapsulation block into the
  AES-GCM associated data (HPKE-style; no unauthenticated bytes). Reads legacy
  v1 hybrid envelopes; AES envelopes unchanged (still v1).
- Fail-fast validation of the default scheme at protector construction, so a
  misconfiguration (e.g. ML-KEM default on an unsupported host) throws at
  startup instead of on first write.
- Pin the patched SQLite native bundle (SQLitePCLRaw 3.x) to clear advisory
  GHSA-2m69-gcr7-jv3q (test/sample-only; not shipped).

API/DX:
- IsEncrypted rejects unsupported property types with a clear, property-named
  error instead of an opaque EF model-build failure.
- In-place, thread-safe key rotation on the in-memory rings (AddKey/
  SetActiveKey/RemoveKey). Required because EF caches the model (and the
  captured protector) per context type, so swapping the ring cannot rotate.
- Re-encryption helpers ReEncryptAsync<T>() and MarkEncryptedPropertiesModified,
  which force EF to re-run the value converter (a plain SaveChanges does not,
  since change tracking compares the unchanged decrypted value).
- Lock the public API surface with Microsoft.CodeAnalysis.PublicApiAnalyzers
  and a PublicAPI.Shipped.txt baseline.

Sample:
- Fix a latent bug where the KEK was disposed inside the configure lambda,
  breaking the sample on any ML-KEM-capable machine.

Docs/versioning:
- README: Always Encrypted/TDE comparison table, "not ASP.NET Data Protection"
  note, rewritten rotation guide, 1.x API + format stability commitment.
- Update KNOWN-GAPS, threat model, migration guide, CHANGELOG; bump to 1.0.0.

Tests expanded from 35 to 55 (envelope hardening + v1 back-compat, fail-fast,
type guard, rotation, re-encryption, concurrency, documented relocation).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes three findings from review (gdm.md):

1. Data loss in online re-encryption. ReEncryptAsync used offset pagination
   (Skip/Take), which can skip an unswept old-key row when concurrent inserts/
   deletes shift rows across a batch boundary — losing that row's plaintext once
   the old key is dropped. Now snapshots primary keys once and fetches each batch
   by key membership (IN), which is immune to row shifting. Rows inserted after
   the snapshot are already under the active key; deleted rows are simply not
   found. Signature is now ReEncryptAsync<TEntity, TKey>() (typed key for the
   snapshot/IN); validates the key type against the model.

2. TOCTOU race retiring keys. The active-key check and dictionary mutation in
   RemoveKey were not atomic, and the id->dictionary indirection could let a
   lock-free ActiveKey read observe a removed key. Rings now hold the active key
   as a direct volatile reference and serialize AddKey/SetActiveKey/RemoveKey
   under a lock, so check-then-act is atomic and reads never dangle.

3. ChangeTracker pollution. ReEncryptAsync operated on the caller's context,
   committing pending changes and evicting the tracked graph. It now requires a
   dedicated context (no tracked entities), reads AsNoTracking, and clears only
   its own batch.

Tests: +3 (online-sweep verifies every row across batches, dedicated-context
guard, key-type mismatch, concurrent rotation stress). 58 pass on net8/net10.
Docs and PublicAPI baseline updated for the new signature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the long-lived NUGET_API_KEY secret with OIDC-based Trusted Publishing:
grant the publish job id-token: write and exchange the GitHub OIDC token for a
short-lived key via NuGet/login before dotnet nuget push. The secret can be
removed from the repo once this ships.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@systemslibrarian systemslibrarian merged commit 96b2244 into main Jul 1, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant