Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions docs/contributing/architecture/data-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,16 @@ The schema is defined by migrations in `packages/worker/migrations/`:
are derived at read time from `community_forks` / `community_stars`
- `secret_buckets`: encrypted-secret ownership buckets scoped to `user`,
`package`, or `session`. Package buckets bind directly to `saved_packages.id`;
package runtimes may use their own package secrets, while user secrets require
an explicit `allowed_packages` grant on every package read path.
package runtimes may use their own package secrets. User secrets are
auto-granted for read/use to self-authored packages (no `community_forks` row
for that `saved_packages.id` + `userId`) and to adopted forks
(`community_forks.adopted_at` set via `community_fork_adopt`; columns in
`0074-community-fork-adoption.sql`). Unadopted community forks
(`community_forks.forked_package_id`, indexed in
`0073-community-forks-forked-package-index.sql`) still require an explicit
`allowed_packages` grant on every package read path. Updating or deleting a
user secret from package code always requires that grant, regardless of fork
or adoption state.

App access pattern:

Expand Down Expand Up @@ -597,8 +605,15 @@ on write unless a migration backfills existing rows.
policy inputs (`0009-secret-allowed-hosts.sql`,
`0010-secret-allowed-capabilities.sql`, `0023-secret-allowed-packages.sql`).
Tightening parse-error behavior requires explicit compatibility review.
`allowed_packages` applies only to user-scoped secrets; package-scoped secrets
are owned exclusively by the package id in their bucket binding.
`allowed_packages` applies only to user-scoped secrets. Unadopted
community-forked packages need it for every package read/use path (provenance
via `community_forks.forked_package_id` + `forker_user_id`; index
`0073-community-forks-forked-package-index.sql`). Self-authored packages and
adopted forks (`community_forks.adopted_at` / `adoption_note` from
`0074-community-fork-adoption.sql`) skip that grant for read/use only.
Mutations from package code (`secret_set` / `secret_delete` / OpenAPI
token-refresh writes) always require the grant. Package-scoped secrets are
owned exclusively by the package id in their bucket binding.
- `package_runtime_runs.metadata_json` and `package_runtime_logs.fields_json`
(`0037-package-runtime-debug.sql`) store bounded debug metadata and log
fields.
Expand Down
3 changes: 2 additions & 1 deletion docs/contributing/secret-host-approval.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ authenticated account admin UI.

In this repo, that means the user must approve host access through the account
secrets experience, such as `/account/secrets` and the focused approval route at
`/account/secrets/approve`.
`/account/secrets/approve`. Capability allowlist changes use the same one-click
"Approve secret access" card on `/account/secrets/<scope>/<name>?capability=…`.

## What agents should assume

Expand Down
8 changes: 6 additions & 2 deletions docs/guides/account-secret-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,12 @@ Provide the user a URL like:

## Package approval URLs (after a package exists)

When a saved package needs access to one or more **existing** user secrets, send
the user an approval link — do not ask them to recreate the secrets.
Self-authored packages and adopted community forks (`community_fork_adopt`) can
read and use the user's secrets without an `allowed_packages` grant; updating or
deleting a user secret from package code still requires that grant. When an
**unadopted community-forked** package needs access to one or more **existing**
user secrets, either adopt it after reviewing the source or send the user an
approval link — do not ask them to recreate the secrets.

- Single secret:
`/account/secrets/user/{secretName}?package_id={savedPackageId}&package={kodyId}`
Expand Down
14 changes: 9 additions & 5 deletions docs/guides/integration-bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,15 @@ app will depend on:
- the agent is using the correct secret names, integration name, and API base
URL

An authenticated `execute` smoke test does **not** grant package secret access.
After you save or publish a secret-using package, surface
`pending_secret_package_approvals` (prefer `bulk_approval_url`), wait for the
user to approve, and verify with `packages.invokeChecked` before calling the
work complete.
An authenticated `execute` smoke test does **not** grant package secret access
for unadopted community-forked packages. Self-authored packages and adopted
forks (`community_fork_adopt` after source review) get automatic read/use access
to user secrets (host approval still applies; updating or deleting a user secret
from package code still needs an `allowed_packages` grant). After you save or
publish a secret-using package, read `pending_secret_package_approvals`; when it
is non-null (unadopted community forks), either adopt after review or surface
`bulk_approval_url`, wait when required, and verify with
`packages.invokeChecked` before calling the work complete.

## Important exceptions

Expand Down
20 changes: 14 additions & 6 deletions docs/guides/package-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,23 @@ When a package will use user-scoped secrets (`{{secret:name}}` placeholders or

1. Ensure each secret exists (see `guide: "connect_secret"` /
`guide: "secret_backed_integration"`).
2. After save/publish, read `pending_secret_package_approvals` from the tool
result.
3. Send the user `bulk_approval_url` when present; otherwise send each
`approval_url`.
4. Wait for approval, then smoke-test with `packages.invokeChecked(...)`.
2. Self-authored packages (and community forks adopted with
`community_fork_adopt` after a real source review) get automatic read/use
access to user secrets (host approval still applies; `secret_set` /
`secret_delete` still need an `allowed_packages` grant). After save/publish,
read `pending_secret_package_approvals` from the tool result — it is non-null
only for unadopted community forks.
3. When pending approvals are present, either review the fork source and call
`community_fork_adopt` with a `review_summary`, or send the user
`bulk_approval_url` / each `approval_url`.
4. Wait for approval or adoption (when required), then smoke-test with
`packages.invokeChecked(...)`.
5. Only then treat the package as ready to run.

Host approval (from an earlier ad hoc `execute` smoke test) is separate from
package approval. Both may be required.
package approval. Unadopted community-forked packages may need both;
self-authored and adopted packages still need host approval when outbound calls
require it.

## Community icon

Expand Down
6 changes: 4 additions & 2 deletions docs/guides/package-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ not tied to reusable package behavior. `job_schedule_once` is the one-off
convenience form.

Use `guide: "package_authoring"` for package shape, README `## Intent`,
visibility guidance, and the secret-using package approval checklist (prefer
bulk approval URLs from `pending_secret_package_approvals` after save/publish).
visibility guidance, and the secret-using package approval checklist
(`pending_secret_package_approvals` is non-null only for unadopted
community-forked packages; prefer `community_fork_adopt` after review, or bulk
approval URLs when present).

## Signals to escalate from `execute` to a package

Expand Down
29 changes: 19 additions & 10 deletions docs/guides/secret-backed-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,21 @@ smoke-test path is unclear.
- Prefer plain package exports for simple automations.
- Use a package app only when the user actually needs interactive UI,
browser-side forms, or hosted callbacks.
8. After the package is saved or published, finish package secret approval.
- An ad hoc `execute` smoke test does **not** grant package secret access.
8. After the package is saved or published, finish package secret approval when
needed.
- Self-authored packages and adopted forks (`community_fork_adopt`) get
automatic read/use access to user secrets (mutations still need an
`allowed_packages` grant); unadopted community forks still need explicit
package approval for read/use, or adoption after review.
- An ad hoc `execute` smoke test does **not** grant package secret access for
community forks.
- Read `pending_secret_package_approvals` from `package_save` or
`package_publish_external_push`.
- Prefer `bulk_approval_url` when present (one click for all listed secrets).
Otherwise send each per-secret `approval_url`.
- Wait for the user to approve, then verify with
`packages.invokeChecked(...)` before treating the package as complete.
`package_publish_external_push` (null for self-authored / adopted
packages).
- When present, either review the source and call `community_fork_adopt`, or
send `bulk_approval_url` / each `approval_url`.
- Wait for the user to approve or for adoption (when required), then verify
with `packages.invokeChecked(...)` before treating the package as complete.

## Secret names and value names

Expand Down Expand Up @@ -174,8 +181,10 @@ Avoid these mistakes:
- saving readable config as a secret
- saving the downstream package before the smoke test passes
- assuming a saved secret automatically approves outbound hosts
- treating an ad hoc `execute` smoke test as package secret approval
- marking a secret-using package complete without sending package approval links
(prefer the bulk approval URL when multiple secrets need access)
- treating an ad hoc `execute` smoke test as package secret approval for a
community-forked package
- marking an unadopted community-forked secret-using package complete without
adopting after review (`community_fork_adopt`) or sending package approval
links (prefer the bulk approval URL when multiple secrets need access)
- inventing a provider-specific flow when one or two secrets plus a smoke test
would do
25 changes: 18 additions & 7 deletions docs/use/secrets-and-values.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@ such as **`package`**) returns **metadata only**: names, descriptions, allowed
hosts, allowed capabilities — not plaintext values.

Package-scoped secrets belong to one saved package and are available only while
that package runs. User-scoped secrets require explicit package approval before
package code can list, read, update, or delete them through mounts, fetch
placeholders, or secret-aware capabilities.
that package runs. User-scoped secrets are available automatically for **reading
and using** (mounts, fetch placeholders, capability inputs) to packages the user
authored themselves, and to community forks the user has adopted with
`community_fork_adopt` after reviewing the source. Unadopted community forks
still require explicit package approval (`allowed_packages`) before those
read/use paths. Updating or deleting a user secret from package code
(`secret_set`, `secret_delete`, OpenAPI token-refresh writes) always requires
the explicit package grant, including for self-authored and adopted packages.
Host and capability approvals are unchanged.

**`kody.secret_set(...)`** persists a value that is already available inside
execution (for example a refreshed OAuth token). It does not return secret
Expand Down Expand Up @@ -104,15 +110,20 @@ does not by itself approve new hosts.

## Package approval

User-scoped secrets also need explicit **package** approval before package code
can use them. Saving a secret, approving a host, or succeeding in an ad hoc
execute smoke test does not grant that access.
Unadopted community-forked packages need explicit **package** approval
(`allowed_packages`) before they can read or use user-scoped secrets.
Self-authored packages and adopted forks (`community_fork_adopt` after a real
source review) get that read/use access automatically. Updating or deleting a
user secret from package code always needs the grant. Saving a secret, approving
a host, or succeeding in an ad hoc execute smoke test does not grant package
access.

When several secrets need the same package approved, Kody can provide a bulk
approval URL shaped like
`/account/secrets/approve?package_id=...&names=secretA,secretB`. That page lists
every pending secret and approves them in one click. Single-secret links still
work for one-off grants.
work for one-off grants. For community forks, reviewing the source and calling
`community_fork_adopt` is an alternative to sending those approval links.

## Values

Expand Down
15 changes: 15 additions & 0 deletions packages/worker/client/routes/account-approval-shared.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@ test('buildHostApprovalRequestUrl maps secret approval links and rejects invalid
).toBe(
'/account/secrets.json?allowed-host=api.github.com&selected=user%3A%3A%3A%3AgithubAccessToken',
)
expect(
buildHostApprovalRequestUrl(
'https://example.com/account/secrets/user/cloudflareToken?capability=secret_set',
'https://example.com',
),
).toBe(
'/account/secrets.json?capability=secret_set&selected=user%3A%3A%3A%3AcloudflareToken',
)
expect(
buildHostApprovalRequestUrl(
'/account/secrets/package/pkg-1/signingSecret?capability=secret_jwt_sign',
),
).toBe(
'/account/secrets.json?capability=secret_jwt_sign&selected=package%3A%3Apkg-1%3A%3AsigningSecret',
)
expect(() =>
buildHostApprovalRequestUrl('/account/secrets?allowed-host=slack.com'),
).toThrow('Invalid approval link.')
Expand Down
1 change: 1 addition & 0 deletions packages/worker/client/routes/account-approval-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type ApprovalView = {
requestedHost: string
requestedCapability: string | null
currentAllowedHosts: Array<string>
currentAllowedCapabilities: Array<string>
requestedPackageId: string | null
currentAllowedPackages: Array<string>
}
Expand Down
Loading
Loading