Skip to content

docs(security): secrets change subscription and live scoped accessor - #584

Merged
kriszyp merged 5 commits into
kris/secrets-docsfrom
dawson/secrets-subscribe-docs
Jul 14, 2026
Merged

docs(security): secrets change subscription and live scoped accessor#584
kriszyp merged 5 commits into
kris/secrets-docsfrom
dawson/secrets-subscribe-docs

Conversation

@dawsontoth

Copy link
Copy Markdown
Contributor

Stacks on #581 (targets its kris/secrets-docs branch). Documents the live secret-change feature that landed after#581 was written, so the secrets page backs the new API instead of still saying "no live re-materialization."

What & why

Feature PR: harper#1787 — Add live secret change subscription and live scoped accessor (implements harper#1776), merged into main (5.2.0-alpha.5). Studio's Secrets config page now shows a secrets.subscribe() example in its inline guidance and links here, so the docs need to cover it.

Changes to reference/security/secrets.md:

  • New ### React to rotations with secrets.subscribe() — documents the async iterable (current value, then every change), with the practical pattern: read the value for immediate use, then subscribe in a background task so a top-level for await doesn't block module load. Covers per-event authority re-eval (revoke/delete → undefined, stream stays open; re-grant resumes on the same iterator) and the reserved subscribe name.
  • Live scoped accessor — the "Read scoped secrets" section now notes that secrets.NAME is live on the scoped tier, and that a destructure is a point-in-time copy (won't observe rotations). Corrected the old "frozen and enumerable" description to the read-only live view, with subscribe as a non-enumerable member.
  • Replaced "Healing after changes" with a per-tier "How each tier sees a change" table: scoped = live (accessor + subscribe); global/process.env = reload-only (deliberate — inherited env + "real env wins" precedence). The reload-only healing note is retained for the global tier.

Ships in v5.2.0 alongside the rest of the secrets store, so no differential <VersionBadge> — the page is uniformly 5.2.0 surface (consistent with #581, which added none).

Note on the extra commit

The first commit (style(operations-api): …) is Prettier table alignment only — no content change. The kris/secrets-docs branch currently fails format:check on both operations.md and secrets.md; since CI runs prettier . --check repo-wide, that has to be clean for this PR to go green. secrets.md's pre-existing formatting is fixed within the content commit (Prettier also added a trailing comma to the jsonc envelope example — valid for that block).

Verification

  • npm run format:write + npm run format:check clean.
  • npm run build succeeds; the new #react-to-rotations-with-secretssubscribe cross-link resolves (the only broken-anchor warning is a pre-existing one on release-notes/v5-lincoln/5.1, unrelated to this change).

🤖 Generated with Claude Code

dawsontothand others added 2 commits July 14, 2026 11:19
Pre-existing format:check violation on the kris/secrets-docs branch; the
repo-wide prettier gate must be clean for CI.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…accessor
Documents harper#1787 (live secret change detection) on the new secrets
reference page:
- secrets.subscribe(name) — async iterable yielding the current value then
every change; shown as read-now + fire-and-forget background subscribe so
module load isn't blocked (the practical hot-swap-on-rotation pattern).
- Live scoped-tier accessor: a fresh secrets.NAME read reflects the latest
value; a destructure is now called out as a point-in-time copy.
- Reworked 'Healing after changes' into a per-tier 'How each tier sees a
change' table (scoped = live; global/process.env = reload-only) and
corrected the 'frozen' accessor description to the read-only live view,
with subscribe as a non-enumerable member.
Ships in v5.2.0 alongside the rest of the secrets store, so no differential
VersionBadge (the page is uniformly 5.2.0 surface).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dawsontoth
dawsontoth requested a review from a team as a code ownerJuly 14, 2026 15:20

@gemini-code-assistgemini-code-assistBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the secrets documentation to explain the live nature of the scoped tier accessor and introduces the new secrets.subscribe() API for handling secret rotations. The review feedback suggests optimizing the provided code example for secrets.subscribe() to avoid a redundant client instantiation on startup by tracking the active key and only re-instantiating when it changes.

Comment threadreference/security/secrets.md
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL:https://preview.harper-documentation.harperfabric.com/pr-584

This preview will update automatically when you push new commits.

@github-actions
github-actionsBot temporarily deployed to pr-584 July 14, 2026 15:22 Inactive
Address review on #584: secrets.subscribe() replays the current value
first, so guard on key change to skip the redundant client rebuild on
startup, and note that semantic inline.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions
github-actionsBot temporarily deployed to pr-584 July 14, 2026 15:26 Inactive
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL:https://preview.harper-documentation.harperfabric.com/pr-584

This preview will update automatically when you push new commits.

@dawsontoth
dawsontoth requested a review from kriszypJuly 14, 2026 15:27
dawsontoth added a commit to HarperFast/studio that referenced this pull request Jul 14, 2026
…ance
The inline 'How to read it in your component' guidance on the cluster
Secrets config page now shows the live-change API from harper#1787:
- Scoped-tier example reads the value immediately, then subscribes in a
fire-and-forget background task so module load isn't blocked, guarding on
change so the first (current-value) yield doesn't trigger a redundant
rebuild. The global/process.env tier stays reload-only (subscribe there is
not live), so its example is unchanged.
- Outward links to the Harper secrets docs (reference/v5/security/secrets):
one contextual link by the code example, one in the config page toolbar.
Docs backing the example: HarperFast/documentation#584.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirror the studio review fix (HarperFast/studio#1501): the fire-and-forget
subscribe loop is copy-paste code, so wrap it in try/catch and console.error
the failure so a stream error can't become an unhandled promise rejection.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions
github-actionsBot temporarily deployed to pr-584 July 14, 2026 15:39 Inactive
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL:https://preview.harper-documentation.harperfabric.com/pr-584

This preview will update automatically when you push new commits.

…ption
Per feedback: reading secrets.NAME (undestructured) returns the live value
on every read, so most components just use the secret where they need it —
e.g. per request inside a resource — and get the current value with no
subscription. Only a destructure takes a snapshot. Reframe subscribe() as
the case for long-lived objects built from a secret (client/pool/signer)
that must be rebuilt on rotation, and make the loader note's per-loader
boundary explicit (vm/compartment read live anywhere; native resolves only
during load).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions
github-actionsBot temporarily deployed to pr-584 July 14, 2026 16:31 Inactive
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL:https://preview.harper-documentation.harperfabric.com/pr-584

This preview will update automatically when you push new commits.

@kriszypkriszyp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accurate secrets docs and the examples handle secrets safely (no lingering plaintext). One minor nit worth a follow-up: the subscribe sample could use an undefined-guard, but nothing blocking. Approving.

🤖 Reviewed with KrAIs (Claude Opus 4.8)

@kriszyp
kriszyp merged commit d0f1579 into kris/secrets-docsJul 14, 2026
7 checks passed
@kriszyp
kriszyp deleted the dawson/secrets-subscribe-docs branch July 14, 2026 18:49
@github-actions

Copy link
Copy Markdown

🧹 Preview Cleanup

The preview deployment for this PR has been removed.

dawsontoth added a commit to HarperFast/studio that referenced this pull request Jul 17, 2026
…ance
The inline 'How to read it in your component' guidance on the cluster
Secrets config page now shows the live-change API from harper#1787:
- Scoped-tier example reads the value immediately, then subscribes in a
fire-and-forget background task so module load isn't blocked, guarding on
change so the first (current-value) yield doesn't trigger a redundant
rebuild. The global/process.env tier stays reload-only (subscribe there is
not live), so its example is unchanged.
- Outward links to the Harper secrets docs (reference/v5/security/secrets):
one contextual link by the code example, one in the config page toolbar.
Docs backing the example: HarperFast/documentation#584.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
dawsontoth added a commit to HarperFast/studio that referenced this pull request Jul 17, 2026
…ance
The inline 'How to read it in your component' guidance on the cluster
Secrets config page now shows the live-change API from harper#1787:
- Scoped-tier example reads the value immediately, then subscribes in a
fire-and-forget background task so module load isn't blocked, guarding on
change so the first (current-value) yield doesn't trigger a redundant
rebuild. The global/process.env tier stays reload-only (subscribe there is
not live), so its example is unchanged.
- Outward links to the Harper secrets docs (reference/v5/security/secrets):
one contextual link by the code example, one in the config page toolbar.
Docs backing the example: HarperFast/documentation#584.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
dawsontoth added a commit to HarperFast/studio that referenced this pull request Jul 22, 2026
…ance
The inline 'How to read it in your component' guidance on the cluster
Secrets config page now shows the live-change API from harper#1787:
- Scoped-tier example reads the value immediately, then subscribes in a
fire-and-forget background task so module load isn't blocked, guarding on
change so the first (current-value) yield doesn't trigger a redundant
rebuild. The global/process.env tier stays reload-only (subscribe there is
not live), so its example is unchanged.
- Outward links to the Harper secrets docs (reference/v5/security/secrets):
one contextual link by the code example, one in the config page toolbar.
Docs backing the example: HarperFast/documentation#584.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ethan-Arrowood pushed a commit that referenced this pull request Jul 27, 2026
…nt registryAuth (#581)
* docs(security): document the secrets store, operations, and deploy_component registryAuth
Adds v5 reference documentation for the encrypted secrets store (#1550/#1554/
#1582) and the deploy_component private-registry auth path (#1717), none of
which was previously documented.
- reference/security/secrets.md (new): store model, custody (Pro) vs OSS core,
the two delivery tiers (process.env global vs scoped grants), the config.yaml
`env:` declaration block, the `import { secrets } from 'harper'` accessor,
full client-side `enc:v1:` envelope format + Node reference client, and the
threat model. Added to the Security sidebar.
- reference/operations-api/operations.md: new Secrets section (set_secret,
grant_secret, revoke_secret, list_secrets, delete_secret,
get_secrets_public_key) plus a registryAuth subsection under deploy_component.
- reference/components/javascript-environment.md: add `secrets` to the Harper
API globals list.
- reference/environment-variables/overview.md: cross-link to the secrets store
as the production alternative to a committed .env.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(security): secrets change subscription and live scoped accessor (#584)
* style(operations-api): apply prettier table alignment
Pre-existing format:check violation on the kris/secrets-docs branch; the
repo-wide prettier gate must be clean for CI.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(security): document secrets change subscription and live scoped accessor
Documents harper#1787 (live secret change detection) on the new secrets
reference page:
- secrets.subscribe(name) — async iterable yielding the current value then
every change; shown as read-now + fire-and-forget background subscribe so
module load isn't blocked (the practical hot-swap-on-rotation pattern).
- Live scoped-tier accessor: a fresh secrets.NAME read reflects the latest
value; a destructure is now called out as a point-in-time copy.
- Reworked 'Healing after changes' into a per-tier 'How each tier sees a
change' table (scoped = live; global/process.env = reload-only) and
corrected the 'frozen' accessor description to the read-only live view,
with subscribe as a non-enumerable member.
Ships in v5.2.0 alongside the rest of the secrets store, so no differential
VersionBadge (the page is uniformly 5.2.0 surface).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(security): dedupe the subscribe example's startup rebuild
Address review on #584: secrets.subscribe() replays the current value
first, so guard on key change to skip the redundant client rebuild on
startup, and note that semantic inline.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(security): guard the subscribe example against unhandled rejections
Mirror the studio review fix (HarperFast/studio#1501): the fire-and-forget
subscribe loop is copy-paste code, so wrap it in try/catch and console.error
the failure so a stream error can't become an unhandled promise rejection.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(security): lead with the live accessor; subscription is the exception
Per feedback: reading secrets.NAME (undestructured) returns the live value
on every read, so most components just use the secret where they need it —
e.g. per request inside a resource — and get the current value with no
subscription. Only a destructure takes a snapshot. Reframe subscribe() as
the case for long-lived objects built from a secret (client/pool/signer)
that must be rebuilt on rotation, and make the loader note's per-loader
boundary explicit (vm/compartment read live anywhere; native resolves only
during load).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* docs(security): rename registryAuth → credentials; document git-host deploy auth
deploy_component's registryAuth field was renamed to a general-purpose
`credentials` array (harper#1797) that now carries both npm-registry
(`registry`) and git-host (`host`) credential entries; the git-over-HTTPS
path (harper#1792) serves the token to git from memory via a credential
helper. Update the operations reference and the secrets page accordingly,
including the derived secret-name conventions and a rename note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(security): mention Studio UI for secrets; address review nits
- Note that Harper Studio offers a graphical interface for managing secrets
(Dawson's suggestion) on both the Secrets page and the operations section.
- Clarify that a string env value is stored plaintext in config.yaml (VCS).
- Add a list_secrets response example.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fix operations API table formatting
Co-Authored-By: Codex <noreply@openai.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Dawson Toth <dawson@harperdb.io>
Co-authored-by: Codex <noreply@openai.com>
Ethan-Arrowood pushed a commit that referenced this pull request Jul 27, 2026
…ices for private repos and registries (#594)
* docs(security): document the secrets store, operations, and deploy_component registryAuth
Adds v5 reference documentation for the encrypted secrets store (#1550/#1554/
#1582) and the deploy_component private-registry auth path (#1717), none of
which was previously documented.
- reference/security/secrets.md (new): store model, custody (Pro) vs OSS core,
the two delivery tiers (process.env global vs scoped grants), the config.yaml
`env:` declaration block, the `import { secrets } from 'harper'` accessor,
full client-side `enc:v1:` envelope format + Node reference client, and the
threat model. Added to the Security sidebar.
- reference/operations-api/operations.md: new Secrets section (set_secret,
grant_secret, revoke_secret, list_secrets, delete_secret,
get_secrets_public_key) plus a registryAuth subsection under deploy_component.
- reference/components/javascript-environment.md: add `secrets` to the Harper
API globals list.
- reference/environment-variables/overview.md: cross-link to the secrets store
as the production alternative to a committed .env.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(security): secrets change subscription and live scoped accessor (#584)
* style(operations-api): apply prettier table alignment
Pre-existing format:check violation on the kris/secrets-docs branch; the
repo-wide prettier gate must be clean for CI.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(security): document secrets change subscription and live scoped accessor
Documents harper#1787 (live secret change detection) on the new secrets
reference page:
- secrets.subscribe(name) — async iterable yielding the current value then
every change; shown as read-now + fire-and-forget background subscribe so
module load isn't blocked (the practical hot-swap-on-rotation pattern).
- Live scoped-tier accessor: a fresh secrets.NAME read reflects the latest
value; a destructure is now called out as a point-in-time copy.
- Reworked 'Healing after changes' into a per-tier 'How each tier sees a
change' table (scoped = live; global/process.env = reload-only) and
corrected the 'frozen' accessor description to the read-only live view,
with subscribe as a non-enumerable member.
Ships in v5.2.0 alongside the rest of the secrets store, so no differential
VersionBadge (the page is uniformly 5.2.0 surface).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(security): dedupe the subscribe example's startup rebuild
Address review on #584: secrets.subscribe() replays the current value
first, so guard on key change to skip the redundant client rebuild on
startup, and note that semantic inline.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(security): guard the subscribe example against unhandled rejections
Mirror the studio review fix (HarperFast/studio#1501): the fire-and-forget
subscribe loop is copy-paste code, so wrap it in try/catch and console.error
the failure so a stream error can't become an unhandled promise rejection.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(security): lead with the live accessor; subscription is the exception
Per feedback: reading secrets.NAME (undestructured) returns the live value
on every read, so most components just use the secret where they need it —
e.g. per request inside a resource — and get the current value with no
subscription. Only a destructure takes a snapshot. Reframe subscribe() as
the case for long-lived objects built from a secret (client/pool/signer)
that must be rebuilt on rotation, and make the loader note's per-loader
boundary explicit (vm/compartment read live anywhere; native resolves only
during load).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* docs(security): rename registryAuth → credentials; document git-host deploy auth
deploy_component's registryAuth field was renamed to a general-purpose
`credentials` array (harper#1797) that now carries both npm-registry
(`registry`) and git-host (`host`) credential entries; the git-over-HTTPS
path (harper#1792) serves the token to git from memory via a credential
helper. Update the operations reference and the secrets page accordingly,
including the derived secret-name conventions and a rename note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(security): mention Studio UI for secrets; address review nits
- Note that Harper Studio offers a graphical interface for managing secrets
(Dawson's suggestion) on both the Secrets page and the operations section.
- Clarify that a string env value is stored plaintext in config.yaml (VCS).
- Add a list_secrets response example.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(components): fix install_allow_scripts field name (install_allowInstallScripts never existed)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(learn): CI/CD deployment guide — git-tag vs registry, deploy credentials, GitHub Actions
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(learn): recommend inline token as the primary credential flow; mention Studio UI for set_secret
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs: fix prettier formatting in deploy-from-CI guide and operations reference
CI's Format Check was failing on markdown table alignment and italic-marker
style in these two files.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* docs(learn): fix CI deploy guide review nits — auth header, secret name typo
- HARPER_OPS_AUTH now documented (and used in the curl examples) as the
full Authorization header value, so a Bearer token works as well as
Basic — the hardcoded "Authorization: Basic $HARPER_OPS_AUTH" would
break for bearer-token users.
- Fix derived secret name example: deploy.my-app.git.github_com ->
deploy.my-app.git.github.com (deriveGitSecretName preserves dots).
Addresses review feedback from gemini-code-assist and cb1kenobi on
PR #594. The heredoc-EOF-indentation concern raised alongside the auth
header comments does not apply here: verified against a YAML parser
that the block-scalar's common-indentation stripping puts EOF at
column 0 in the actual generated script, since it shares curl's base
indent.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Dawson Toth <dawson@harperdb.io>
Sign up for freeto 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.

2 participants

@dawsontoth@kriszyp