Skip to content

chore(ci): gate the build on deprecated and non-existent API in docs#61

Merged
coderdan merged 10 commits into
v2from
chore/deprecated-api-lint
Jul 9, 2026
Merged

chore(ci): gate the build on deprecated and non-existent API in docs#61
coderdan merged 10 commits into
v2from
chore/deprecated-api-lint

Conversation

@coderdan

@coderdan coderdan commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Stacked on #60 (merge main into v2). Review that first; this PR's diff against v2 will show #60's changes until it lands.

Why

Twice today the same class of bug bit us:

Neither was caught by anything. Two long-lived content branches plus a fast-moving SDK means a fix on one branch is not a fix, and code review is the only thing standing between a stale port and production.

What it does

bun run validate-content, wired into prebuild, scans content/docs and content/stack for API that is:

Rule Catches
lockcontext-identify .identify( — deprecated in protect-ffi 0.25; the token it fetches no longer affects encryption
identity-token-option withLockContext({ identityToken }) — never existed in any release
bare-lockcontext-constructor new LockContext() — only useful with the deprecated flow
eql-v2-encrypted-type eql_v2_encrypted — removed in EQL 3.0.0
eql-v2-schema-functions eql_v2.*() calls
eql-v2-config-table cs_add_column_v1, cs_match_v1, cs_ste_vec_v2, add_search_config, …
protect-branding ProtectClientConfig, @cipherstash/cli

Each failure prints the file, line, offending text, and the fix.

Two design decisions

Rules are scoped. The EQL v3 rules apply only to content/docs. The legacy tree documents EQL v2 throughout by design, and content/docs/reference/eql/v2/ is a deliberately retained v2 reference. Both would otherwise drown the output.

A line is exempt when it says the API is retired. The exemption matches deprecated | removed | no longer | are gone | never existed, so deprecation callouts and migration notes can name the old API in order to warn readers off it. Naming a dead symbol without saying it's dead is the bug; that's the line the check draws.

This also means the check is line-local and greppable rather than an AST pass. It's a tripwire, not a type checker. The real fix for snippet correctness is snippet type-checking against the published packages, which is still open as part of the correctness-CI work.

Verification

Not just "it passes". I replayed both regressions:

# PR #43's original aws-kms.mdx (commit 6db2352)
✗ 2 occurrence(s) ...
  [lockcontext-identify]  content/docs/concepts/compare/aws-kms.mdx:131
  [bare-lockcontext-constructor]  content/docs/concepts/compare/aws-kms.mdx:131

# main's pre-#57 compliance.mdx (commit 94e526e)
  [identity-token-option]  .withLockContext({ identityToken: billingServiceJWT })

Both flagged. And it passes on the current tree:

✓ no deprecated or non-existent API found in documentation

bun run build passes with the guard running in prebuild, 714 pages. biome check clean.

Note

This deliberately pulls the deprecated-API subset of the correctness-CI work forward, ahead of snippet type-checking. It's ~150 lines and it protects the v2 branch for the rest of the migration, which has 58 pages still to port.

coderdan added 10 commits July 8, 2026 12:41
…abase docs

The v2 docs branch will host the Supabase page at /docs/integrations/supabase
but isn't published yet. Add a temporary (307) redirect from that future URL to
the current Supabase overview page (/stack/cipherstash/supabase) so external
links resolve until v2 ships, at which point this entry should be removed.
…ons-supabase

chore(redirects): temp redirect /integrations/supabase → current Supabase docs
… build

The EQL reference generator fetches the latest release's API.md at build time
and passes lowercase-led tags (e.g. `<tt>`) through as real HTML. MDX requires
every tag to be balanced, so a mangled SQL-comment source that emits an
unclosed `<tt>` fails the whole Vercel build — which is exactly what
eql-3.0.0-alpha.3 did (index.mdx:2153, `Expected a closing tag for <tt>`).

`<tt>` is Doxygen's teletype tag; MDX doesn't need it. Strip `<tt>`/`</tt>`
(non-code text only) before escaping, so malformed upstream docs degrade
gracefully instead of taking the deploy down.

Verified: regenerated content/stack/reference/eql/index.mdx from the live
eql-3.0.0-alpha.3 release and `next build` compiles all 329 pages.
fix(eql-docs): strip Doxygen <tt> tags so a stray one can't break the build
The live docs teach `new LockContext().identify(jwt)`. Per-operation CTS
tokens were removed in protect-ffi 0.25, so `identify()` is deprecated: it
still compiles and logs a warning, but the token it fetches is no longer
used by encryption operations. Readers copying these examples get code that
appears to bind an identity and does not.

Correct usage authenticates the client as the end user with
OidcFederationStrategy (config.authStrategy), then names the claim to bind:

  const client = await Encryption({
    schemas: [users],
    config: { authStrategy: OidcFederationStrategy.create(crn, () => getJwt()) },
  })
  await client.encrypt(v, opts).withLockContext({ identityClaim: ["sub"] })

Two pages also used `client.withLockContext({ identityToken })`, a call shape
that never existed in any release.

Verified against the shipped type definitions of @cipherstash/stack 0.19.0
and @cipherstash/auth 0.42.0.
docs: update identity-aware encryption to the strategy-based API
Follow-up to #57, from review feedback on the v2 port (#56).

The client setup blocks configure `authStrategy`, but the examples below
them import an already-built client, so a reader skimming the encrypt and
decrypt snippets sees `.withLockContext()` with no strategy in view and
could reasonably conclude the claim binding stands alone.

- Warn that OidcFederationStrategy is the only strategy supporting lock
  contexts. AccessKeyStrategy authenticates as the service, so there is no
  end-user identity for ZeroKMS to resolve the claim against.
- State that the examples depend on the authStrategy-configured client.
- Explain that `_` in the dashboard OIDC providers URL is the selected
  workspace.

Dropped the "AccessKeyStrategy is also re-exported" aside from identity.mdx:
naming it in a lock-context section was what invited the confusion.
…arifications

docs: clarify that lock contexts require OidcFederationStrategy
Brings the identity-API fixes (#57, #59) and the EQL docs build fix (#58)
into the v2 branch. Without this, merging v2 to main at launch would revert
them: v2's copy of content/stack still taught LockContext.identify(), which
is deprecated and no longer affects encryption.

One conflict, in scripts/generate-eql-docs.ts. Both branches carry the same
`<tt>`-stripping fix; they differ only in whether the .replace chain is
wrapped in parentheses. Kept v2's formatting.
A page fixed on one branch gets silently reintroduced by a port from the
other. That is how `LockContext.identify()` survived being fixed on main and
came back through a comparison-page port (#43), and how v2's legacy tree kept
teaching it after main was fixed (#60).

`validate-content` scans content/docs and content/stack for API that is
deprecated (LockContext.identify), never existed (withLockContext with an
identityToken option), or was removed in EQL 3.0.0 (eql_v2_encrypted,
add_search_config, the cs_*_v1 config functions), plus stale `protect` and
`@cipherstash/cli` branding.

Rules are scoped: EQL v3 rules apply only to content/docs, since the legacy
tree documents EQL v2 by design. Generated output is skipped; those examples
come from the SDK's own doc comments and get fixed upstream.

A line is exempt when it also says the API is retired, so deprecation
callouts and migration notes can still name the old API in order to warn
readers off it. Naming a dead symbol without saying it is dead is the bug.

Verified against both real regressions: it flags PR #43's original aws-kms
snippet and main's pre-#57 `identityToken` form, and passes on the current
tree.
@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
public-docs Ready Ready Preview, Comment Jul 9, 2026 6:31am

Request Review

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