Skip to content

Commit 995d65c

Browse files
committed
fix(stack-encrypt): address the review of removing target::legacy
The review of the removal found no slip in the rewritten tests. It found four places where the prose was incomplete or out of date. - CHANGELOG: the upgrade note gave no replacement for P::decrypt_from(stored, &cipher), and did not say how to name the target that Target::encrypt_from named in its path. It now has a table with one replacement for each removed call. It also warns that a source that is already a reference must be passed as it is. The removed methods took it through method-call autoref, so a &String receiver encrypted a String. encrypt_as(&value, ..) on a &String encrypts a &String, and into StackCipherText that compiles. - tests/ui/bare_context.rs: the module doc described the _with_context forms, which the cases no longer call. It now says what the snapshot pins: a &str does not convert into a context. - ADR-0012 said the target::legacy helpers stay until plans, EQL, Go and the guest move to the owned API. They are now removed first. - The API plan: a stray comma in one code comment.
1 parent 36ee93f commit 995d65c

4 files changed

Lines changed: 34 additions & 16 deletions

File tree

‎docs/plans/2026-10-24-stack-encrypt-api-plan.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,8 @@ let email = Identifier::for_column("members", "email")?;
293293
let age = Identifier::for_column("members", "age")?;
294294

295295
// Not on `next` yet: the new traits for EQL types, and a borrowed value
296-
// and context. Today this needs `keyset.encrypt_as(&value, context)`,
297-
// and an owned context.
296+
// and context. Today this needs `keyset.encrypt_as(&value, context)`
297+
// with an owned context.
298298
let by_email: TextEqQuery = "alice@example.com"
299299
.encrypt_into_with_context(&keyset, Scope::new(&email))
300300
.await?;

‎packages/stack-encrypt/CHANGELOG.md‎

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
104104
- To upgrade a type that implements only `EncryptFrom` or
105105
`DecryptInto`, call the cipher. The context is `T::Context`, so
106106
convert it with `into()`:
107-
`keyset.encrypt_as(&value, context.into())`,
108-
`keyset.encrypt_as(&value, Default::default())` for a record with no
109-
caller context, and `cipher.decrypt_as(stored, context.into())`.
107+
108+
| Removed call | Replacement |
109+
| --- | --- |
110+
| `value.encrypt_into(&keyset)` | `keyset.encrypt_as(&value, Default::default())` |
111+
| `value.encrypt_into_with_context(&keyset, context)` | `keyset.encrypt_as(&value, context.into())` |
112+
| `Target::encrypt_from(&value, &keyset, context)` | `keyset.encrypt_as::<_, Target>(&value, context.into())` |
113+
| `stored.decrypt_into(&cipher, context)` | `cipher.decrypt_as(stored, context.into())` |
114+
| `P::decrypt_from(stored, &cipher)` | `cipher.decrypt_as::<P, _>(stored, Default::default())` |
115+
| `P::decrypt_from_with_context(stored, &cipher, context)` | `cipher.decrypt_as::<P, _>(stored, context.into())` |
116+
117+
`encrypt_as` does not name the target, so name it with a type
118+
annotation on the result or with the turbofish shown.
119+
- If `value` is already a reference, pass it as it is:
120+
`keyset.encrypt_as(value, ..)`. The removed methods took the value
121+
through method-call autoref, so a `&String` receiver encrypted a
122+
`String`. `encrypt_as(&value, ..)` on a `&String` encrypts a
123+
`&String` instead. Into a derived record that is a compile error.
124+
Into `StackCipherText` it compiles, because that target accepts any
125+
`Encrypt` source.
110126

111127
- **`target::ExpectedContext` is no longer part of the API** (#1488). It
112128
is the check that a `#[stash(context_field)]` record runs on decrypt:

‎packages/stack-encrypt/docs/adr/0012-owned-record-declarations.md‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
status: accepted
33
date: 2026-11-03
4-
revised: 2026-11-09
4+
revised: 2026-11-11
55
extends: ADR-0003, ADR-0004
66
---
77

@@ -198,9 +198,11 @@ with a hand-written `EncryptTarget`, with the derive, and with a data plan.
198198
All three give the same descriptors and the same search term bytes, and each
199199
decrypts the records of the other two.
200200

201-
The plan removes the structural traits, the `encrypt_as` and `decrypt_as`
202-
calls, and the helpers in `target::legacy`. They stay until plans, EQL, Go,
203-
and the guest have moved to the owned API.
201+
The plan removes the structural traits and the `encrypt_as` and
202+
`decrypt_as` calls. They stay until plans, EQL, Go, and the guest have moved
203+
to the owned API. The helpers in `target::legacy` were removed first. They
204+
were only a second way to call `encrypt_as` and `decrypt_as`, so their
205+
callers now call those methods.
204206

205207
### 6. The structural `Vec` decrypts through the wiping path
206208

‎packages/stack-encrypt/tests/ui/bare_context.rs‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
//! The `_with_context` forms take anything that converts into a
2-
//! `NonEmpty<_>` — a `nonempty!(..)` literal, a `NonEmpty::new(..)?` value,
3-
//! a bare integer — and nothing unproven: a `&str` is not a context until it
4-
//! has been checked, so it is turned away at the call, not at a leaf. That
5-
//! holds on every path that reaches a leaf — a term, a struct record, a
6-
//! plaintext-derived record, a leaf opened directly — so the proof cannot be
7-
//! skipped by passing the raw value.
1+
//! A context converts from a `NonEmpty<_>`: a `nonempty!(..)` literal, a
2+
//! `NonEmpty::new(..)?` value, or a bare integer. It does not convert from
3+
//! anything unchecked. A `&str` is not a context until it has been checked,
4+
//! so `"..".into()` does not compile, and the value never reaches a leaf.
5+
//! This holds on every path to a leaf: a term, a struct record, a
6+
//! plaintext-derived record, and a leaf opened directly. So the check cannot
7+
//! be skipped by passing the raw value.
88
use stack_encrypt::sem::EqualityTerm;
99

1010
use stack_encrypt::{DecryptInto, EncryptFrom, KeysetCipher, StackCipher, StackCipherText};

0 commit comments

Comments
 (0)