Skip to content

Commit a86711f

Browse files
authored
Merge pull request #1047 from cipherstash/chore/publish-stack-encrypt-crates
chore(release): publish stack-kms, stack-encrypt and stack-encrypt-derive to crates.io
2 parents 39a341f + 1492458 commit a86711f

21 files changed

Lines changed: 189 additions & 97 deletions

File tree

‎.github/workflows/release-plz.yml‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,10 @@ jobs:
181181
# FROZEN_PUBLISHERS (an npm map), so the switch keys on the
182182
# `@cipherstash/auth` entry, which that PR deleted when crates.io and npm
183183
# trusted publishing moved here together. crates.io needs a Trusted
184-
# Publishing entry for both crates naming cipherstash/stack + release-plz.yml.
184+
# Publishing entry for every published crate naming cipherstash/stack +
185+
# release-plz.yml.
185186
#
186-
# Publish-only: nothing here opens a release PR, so a version bump of the two
187+
# Publish-only: nothing here opens a release PR, so a version bump of these
187188
# crates is a hand-made pull request. `release-plz update` cannot version
188189
# this workspace yet: it walks back to the commit that matches crates.io
189190
# 0.42.3, and the imported history has no root Cargo.toml there. A
@@ -209,29 +210,28 @@ jobs:
209210
run: node scripts/eql-pipeline-armed.mjs crates
210211

211212
release-crates:
212-
name: "Release stack-auth and stack-profile"
213+
name: "Release the stack-* crates"
213214
needs: [crates-armed]
214215
if: needs.crates-armed.outputs.armed == 'true'
215216
runs-on: ubuntu-latest
216217
timeout-minutes: 30
217218
permissions:
218-
contents: write # the stack-auth-v<V> / stack-profile-v<V> tags and releases
219+
contents: write # the <crate>-v<V> tags and releases
219220
pull-requests: write # release-plz links PRs in release notes
220221
id-token: write # crates.io Trusted Publishing
221222
steps:
222223
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
223224
with:
224225
fetch-depth: 0
225226

226-
- name: Is either crate version unpublished?
227-
# The EQL preflight's crates.io question, per crate of the version
228-
# group. It decides whether the GPG import runs; an API failure reads
227+
- name: Is any crate version unpublished?
228+
# The EQL preflight's crates.io question, per published crate. It decides whether the GPG import runs; an API failure reads
229229
# as "unpublished", which fails towards importing the key.
230230
id: preflight
231231
run: |
232232
set -euo pipefail
233233
publish_needed=false
234-
for crate in stack-auth stack-profile; do
234+
for crate in stack-auth stack-profile stack-kms stack-encrypt stack-encrypt-derive; do
235235
version="$(grep -m1 '^version = ' "packages/${crate}/Cargo.toml" | cut -d'"' -f2)"
236236
# crates.io 403s curl's default User-Agent.
237237
published="$(curl -fsSL --retry 3 -H "User-Agent: cipherstash-stack-release (https://github.com/cipherstash/stack)" "https://crates.io/api/v1/crates/${crate}/versions" | jq -r '.versions[].num' | grep -Fx "$version" || true)"

‎.github/workflows/tests-crates.yml‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,17 @@ jobs:
139139
- name: Build the stack-encrypt examples
140140
run: cargo build --locked -p stack-encrypt --examples
141141

142+
# The crates release-plz publishes from 0.1.0. `--dry-run` packages and
143+
# compiles each the way crates.io would (the three together, so
144+
# stack-encrypt resolves the other two from cargo's temporary local
145+
# registry), catching a publish-blocker on the PR instead of in
146+
# release-crates on main: missing metadata, or a runtime path dependency
147+
# with no `version`. No token. `--allow-dirty` tolerates files earlier
148+
# steps leave in the tree. Once a version is on crates.io, cargo warns
149+
# rather than fails on a dry run of it.
150+
- name: Verify the stack-encrypt crates package cleanly for crates.io
151+
run: cargo publish --locked --dry-run --allow-dirty -p stack-kms -p stack-encrypt-derive -p stack-encrypt
152+
142153
node-bindings:
143154
name: node bindings, napi typings, stack-auth-wasm
144155
runs-on: blacksmith-16vcpu-ubuntu-2204

‎AGENTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ Every npm package except EQL lives under `languages/typescript/`: packages in `l
9090
EQL issues in this repository, never in the historical
9191
`cipherstash/encrypt-query-language` repository. Old upstream issue and PR
9292
links are provenance only.
93-
- `packages/stack-auth`, `packages/stack-profile`, `packages/stack-kms`, `packages/stack-encrypt`, `packages/stack-encrypt-derive`, `packages/stack-guest-abi`: The Rust crates imported from `cipherstash/cipherstash-suite` with their history — `stack-auth` and `stack-profile` (published to crates.io), and `stack-kms`, `stack-encrypt`, `stack-encrypt-derive` and `stack-guest-abi` (`publish = false`). They are the members of the **root Cargo workspace**, with the three node binding crates below. See "Working on the Rust crates".
93+
- `packages/stack-auth`, `packages/stack-profile`, `packages/stack-kms`, `packages/stack-encrypt`, `packages/stack-encrypt-derive`, `packages/stack-guest-abi`: The Rust crates imported from `cipherstash/cipherstash-suite` with their history — `stack-auth` and `stack-profile` (published to crates.io, one version group), `stack-kms` (published to crates.io from 0.1.0, its own version group, re-exported by `stack-encrypt` as `stack_encrypt::kms`), `stack-encrypt` and `stack-encrypt-derive` (published to crates.io from 0.1.0, one version group; `eql-bindings`' `stack-encrypt` feature depends on them from the registry), and `stack-guest-abi` (`publish = false`). They are the members of the **root Cargo workspace**, with the three node binding crates below. See "Working on the Rust crates".
9494
- `languages/typescript/packages/auth`, `languages/typescript/packages/profile`, `languages/typescript/packages/stack-auth-wasm`: The node bindings of those crates. `@cipherstash/auth` (napi-rs v2) and its six `platforms/*` packages are published to npm from this repository by `release.yml` (`auth-artifacts`, `publish-auth`); a change to what it ships, the `stack-auth` crate included, needs an `@cipherstash/auth` changeset (`require-auth-npm-changeset.yml`). `@cipherstash/profile` and its platforms are private and never published; `@cipherstash/stack-auth-wasm` is private and builds the wasm that `@cipherstash/auth` ships. Their `build` and `test` scripts never invoke cargo; `build:native`, `build:debug` and `test:cargo` do.
9595
- `languages/golang`: The Go module (`stackencrypt`, `stackauth`, `internal`), a wazero host with no cgo. Its two WASI guests (`*/guest`) are detached Cargo workspaces built by `mise run wasm:guest:build` and `mise run wasm:auth-guest:build`; the `.wasm` files they embed are gitignored. There is no Go release process yet.
9696
- `e2e/*`: Cross-package end-to-end tests (package managers, supply chain, Prisma example README)

‎Cargo.lock‎

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ exclude = [
3333

3434
[workspace.package]
3535
# Used by the node binding crates, which take `version.workspace`. The
36-
# published crates (stack-auth, stack-profile) carry their own version.
36+
# published crates (stack-auth, stack-profile, stack-kms, stack-encrypt,
37+
# stack-encrypt-derive) carry their own version.
3738
version = "0.35.0"
3839
edition = "2021"
3940
authors = [
@@ -62,8 +63,8 @@ lto = true # same as "fat"
6263
incremental = true
6364

6465
[workspace.dependencies]
65-
# The two published crates of this workspace. Members take them with
66-
# `workspace = true`.
66+
# stack-auth and stack-profile, two of this workspace's published crates.
67+
# Members take them with `workspace = true`.
6768
# `default-features = false`: a member can add features to a workspace dep
6869
# but cannot subtract them, and `stack-kms` / `stack-encrypt` need stack-auth
6970
# without `http`. Consumers that want the default transport re-enable it with

‎SECURITY.md‎

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,30 @@ This repository also carries the source of the **`eql-bindings`** Rust crate
2828
lockstep with `@cipherstash/eql`. It is in scope for security reports on the
2929
same terms as the npm packages above.
3030

31-
It also carries the source of two Rust crates published to crates.io,
31+
It also carries the source of five Rust crates published to crates.io,
3232
**`stack-auth`** and **`stack-profile`** (`packages/stack-auth`,
33-
`packages/stack-profile`), and of the **Go module** at `languages/golang`
34-
(`stackencrypt` and `stackauth`, over WASI guests built from the stack-*
35-
crates), which has no release yet. All three are in scope for security reports
36-
on the same terms as the npm packages above.
33+
`packages/stack-profile`) and **`stack-kms`**, **`stack-encrypt`** and
34+
**`stack-encrypt-derive`** (`packages/stack-kms`, `packages/stack-encrypt`,
35+
`packages/stack-encrypt-derive`), and of the **Go module** at
36+
`languages/golang` (`stackencrypt` and `stackauth`, over WASI guests built
37+
from the stack-* crates), which has no release yet. All of these are in scope
38+
for security reports on the same terms as the npm packages above.
39+
40+
The five stack-* crates are licensed under the PolyForm Internal Use License
41+
1.0.0 (each crate's `LICENSE`), not the repository's MIT licence: they may be
42+
used for internal business operations only, and not redistributed. That
43+
includes the optional `stack-encrypt` feature of the MIT-licensed
44+
`eql-bindings` crate, which depends on `stack-encrypt` and so is usable only
45+
under the same terms.
3746

3847
> **Note on publishing.** Every package in the table above, including all
3948
> seven `@cipherstash/protect-ffi*` packages, all seven `@cipherstash/auth*`
4049
> packages and `@cipherstash/eql`, is published from this repository by
41-
> `.github/workflows/release.yml`; the `eql-bindings`, `stack-auth` and
42-
> `stack-profile` crates are published from here by
43-
> `.github/workflows/release-plz.yml`. EQL moved here at the Phase 5 cutover in
50+
> `.github/workflows/release.yml`; the `eql-bindings`, `stack-auth`,
51+
> `stack-profile`, `stack-kms`, `stack-encrypt` and `stack-encrypt-derive`
52+
> crates are published from here by `.github/workflows/release-plz.yml` (the
53+
> first version of each of the last three was published by hand, because
54+
> crates.io configures Trusted Publishing on an existing crate). EQL moved here at the Phase 5 cutover in
4455
> `docs/plans/2026-08-13-eql-monorepo-absorption.md`, and the auth packages and
4556
> the two crates at the arming PR of the stack-* crates import. Releases made
4657
> before those moves were built elsewhere: `@cipherstash/eql@3.0.5` and earlier
@@ -168,8 +179,9 @@ CI. See `skills/stash-supply-chain-security/SKILL.md` for the full guide.
168179
The `release.yml` workflow publishes packages to npm using OIDC trusted
169180
publishing (`id-token: write`). There is no long-lived `NPM_TOKEN` — the
170181
workflow deliberately avoids one, and setting one would bypass trusted
171-
publishing. `release-plz.yml` publishes the `eql-bindings` crate to crates.io
172-
over the same token exchange, and likewise carries no `CARGO_REGISTRY_TOKEN`.
182+
publishing. `release-plz.yml` publishes the `eql-bindings` crate and the stack-* crates to
183+
crates.io over the same token exchange, and likewise carries no
184+
`CARGO_REGISTRY_TOKEN`.
173185
Both bind to a *workflow filename* at the registry, so renaming either file
174186
silently invalidates its publisher configuration.
175187

‎packages/stack-encrypt-derive/Cargo.toml‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ homepage.workspace = true
99
keywords.workspace = true
1010
categories.workspace = true
1111
license-file = "LICENSE"
12-
# Not yet released, like stack-encrypt (which is the only crate that should
13-
# depend on this one: the macros are re-exported from there).
14-
publish = false
12+
# Published to crates.io by release-plz.yml, in the `stack-encrypt` version
13+
# group: stack-encrypt is the only crate that should depend on this one (the
14+
# macros are re-exported from there), and the two release together.
1515

1616
[lib]
1717
proc-macro = true
@@ -24,12 +24,13 @@ syn = { version = "3", features = ["full", "extra-traits"] }
2424
# The dev-dependencies below are used only by the crate-level doctests.
2525
# `cargo-udeps` cannot see into rustdoc, so it reports them as unused.
2626
[package.metadata.cargo-udeps.ignore]
27-
development = ["stack-encrypt", "stack-kms", "tokio"]
27+
development = ["stack-encrypt", "tokio"]
2828

2929
[dev-dependencies]
3030
# The crate-level examples are real doctests, run against the fake key
3131
# source. A dev-dependency cycle back to `stack-encrypt` is the usual shape
32-
# for a derive crate (cf. serde_derive -> serde).
33-
stack-encrypt = { path = "../stack-encrypt" }
34-
stack-kms = { path = "../stack-kms", features = ["test-support"] }
32+
# for a derive crate (cf. serde_derive -> serde). The fake key source comes
33+
# through stack-encrypt's `test-support` feature, as a user's tests take it, so
34+
# these doctests are what exercises that forwarding.
35+
stack-encrypt = { path = "../stack-encrypt", features = ["test-support"] }
3536
tokio = { workspace = true, features = ["rt", "macros"] }

‎packages/stack-encrypt-derive/src/lib.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//! ```
77
//! use stack_encrypt::{EncryptFrom, DecryptInto, StackCipher, StackCipherText, nonempty};
88
//! use stack_encrypt::sem::EqualityTerm;
9-
//! use stack_kms::FakeDataKeySource;
9+
//! use stack_encrypt::kms::FakeDataKeySource;
1010
//!
1111
//! #[derive(EncryptFrom, DecryptInto)]
1212
//! #[stash(plaintext = String)]
@@ -63,7 +63,7 @@
6363
//! CipherText, Decryptable, Encrypt, EncryptFrom, Encryption, Error, SealedValue, StackCipher,
6464
//! nonempty,
6565
//! };
66-
//! use stack_kms::FakeDataKeySource;
66+
//! use stack_encrypt::kms::FakeDataKeySource;
6767
//!
6868
//! /// A column that stores one sealed leaf as bytes.
6969
//! struct LeafBytes(Vec<u8>);

‎packages/stack-encrypt/Cargo.toml‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,20 @@ homepage.workspace = true
99
keywords.workspace = true
1010
categories.workspace = true
1111
license-file = "LICENSE"
12-
# Not yet released: keep release-plz from picking this crate up (it processes
13-
# any workspace crate whose Cargo.toml lacks `publish = false`).
14-
publish = false
12+
# Published to crates.io by release-plz.yml; release-plz.toml puts it in the
13+
# `stack-encrypt` version group.
1514

1615
[dependencies]
1716
# `profile` (native only; stack-kms gates it off wasm32 itself) lets
1817
# `StackCipher::new()` fall back to the client key `stash auth login` writes
1918
# to the profile directory (`secretkey.json`) when CS_CLIENT_ID /
2019
# CS_CLIENT_KEY are not set — the same place `AutoStrategy` finds the token.
21-
stack-kms = { path = "../stack-kms", default-features = false, features = ["profile"] }
20+
stack-kms = { path = "../stack-kms", version = "0.1.0", default-features = false, features = ["profile"] }
2221
# `StackCipher::new()` builds a ZeroKMS client from the environment, so its
2322
# return type names the auto-detected auth strategy. Only needed with `http`.
2423
stack-auth = { workspace = true, optional = true }
2524
# `#[derive(EncryptFrom)]` / `#[derive(DecryptInto)]`, re-exported from `target`.
26-
stack-encrypt-derive = { path = "../stack-encrypt-derive" }
25+
stack-encrypt-derive = { path = "../stack-encrypt-derive", version = "0.1.0" }
2726

2827
# The workspace vitaminc (0.5.0): one canonical context encoding shared by
2928
# the AEAD and PRF derivations (`IntoContext`, cipherstash/vitaminc#339),
@@ -58,6 +57,10 @@ http = ["dep:stack-auth", "stack-auth/http", "stack-kms/http"]
5857
# only at runtime, as an FFI binding's are. Off by default — it is only of
5958
# use to a binding author, and it pulls `vitaminc-aead-value` in.
6059
dynamic = ["dep:vitaminc-aead-value"]
60+
# `stack_encrypt::kms::FakeDataKeySource`: the in-memory key source for tests
61+
# with no ZeroKMS, so a caller's dev-dependency on stack-encrypt is enough and
62+
# no direct stack-kms dependency has to agree with this crate's.
63+
test-support = ["stack-kms/test-support"]
6164

6265
[dev-dependencies]
6366
serde_json = { workspace = true }

‎packages/stack-encrypt/examples/zerokms_auth.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
//! anywhere, and CI builds it either way.
1515
1616
use stack_auth::{AuthError, AuthStrategyFn, SecretToken, ServiceToken};
17+
use stack_encrypt::kms::{EnvKeyProvider, StackKmsBuilder};
1718
use stack_encrypt::StackCipher;
18-
use stack_kms::{EnvKeyProvider, StackKmsBuilder};
1919

2020
#[tokio::main(flavor = "current_thread")]
2121
async fn main() -> Result<(), Box<dyn std::error::Error>> {

0 commit comments

Comments
 (0)