mirror of
https://github.com/saltbo/zpan.git
synced 2026-08-29 00:01:42 +08:00
docs(v2.9): define agent access architecture
This commit is contained in:
@@ -19,6 +19,7 @@ Core architecture: clients upload directly to S3-compatible storage via presigne
|
||||
- [docs/architecture.md](docs/architecture.md) — system architecture, tech decisions, platform abstraction
|
||||
- [docs/design/admin-form-ui.md](docs/design/admin-form-ui.md) — admin form layout, density, required/help/placeholder rules
|
||||
- [docs/design/upload-policies.md](docs/design/upload-policies.md) — proposed selector-based upload placement policies for multiple storage backends
|
||||
- [docs/design/agent-authentication.md](docs/design/agent-authentication.md) — Agent OAuth, CI API keys, protocol-neutral authorization, Restish credential handling, and future Agent Auth compatibility
|
||||
- [V2_ROADMAP.md](V2_ROADMAP.md) — product positioning, release plan (v2.0–v2.9)
|
||||
- [docs/roadmap/](docs/roadmap/) — per-version technical specs (v2.0.md–v2.9.md)
|
||||
- [docs/design/spaces-quota-sharing.md](docs/design/spaces-quota-sharing.md) — spaces/quota/sharing design decisions (team billing, allocation, cross-space transfer, no per-item ACL)
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ Three scenarios, one platform:
|
||||
|
||||
- **Image Hosting** — Upload via PicGo / uPic / ShareX / API, get a permanent URL on your own domain
|
||||
- **File Sharing** — Upload, generate a link, distribute
|
||||
- **Automation & Sync** — Agent-friendly CLI for scripted file management, plus a server-side sync protocol for future desktop clients
|
||||
- **Automation & Sync** — Agent-friendly OpenAPI + Restish + upload plugin + Skill workflows for scripted file management, plus a server-side sync protocol for future desktop clients
|
||||
|
||||
## Target Users
|
||||
|
||||
@@ -37,7 +37,7 @@ Each version ships 1–2 major features. Ship small, ship often.
|
||||
| [v2.6](docs/roadmap/v2.6.md) | **Pro / Business Launch** | Cloud binding, entitlement system, white-label, audit log, quota store machinery, site announcements, retroactive gates |
|
||||
| [v2.7](docs/roadmap/v2.7.md) | **WebDAV & File Processing** | WebDAV protocol access, small-file zip compression/extraction, and Community remote-download orchestration through Aria2, qBittorrent, and future adapters |
|
||||
| [v2.8](docs/roadmap/v2.8.md) | **Admin Analytics & Dashboard** | Admin overview, usage/cost/reliability metrics, share analytics, and offline result coverage |
|
||||
| [v2.9](docs/roadmap/v2.9.md) | **Agent CLI** | Scriptable CLI for agents and CI: upload/manage files, shares, spaces, quota, and tasks |
|
||||
| [v2.9](docs/roadmap/v2.9.md) | **Agent Access** | Unified OpenAPI + Restish + upload plugin + Skill, protocol-neutral authorization, delegated OAuth, and workspace-scoped CI keys |
|
||||
| [v2.10](docs/roadmap/v2.10.md) | **Desktop Sync Foundation** | Sync device model, change log, sync API contract, conflict model, and protocol tests for external clients |
|
||||
| Future | **Native Client Projects** | macOS File Provider, Windows/Linux sync clients, Flutter/mobile clients, and other OS-specific apps in separate repositories |
|
||||
| Future | **Enterprise Identity & Governance** | SAML, LDAP / SCIM, advanced RBAC/custom roles, retention, and admin support mode if demand proves real |
|
||||
@@ -76,7 +76,7 @@ Everything an individual, family, or small team needs to self-host:
|
||||
- One personal workspace plus one extra team workspace, shared folders, and basic roles
|
||||
- Small-file zip compression and extraction within local runtime limits
|
||||
- Remote-download orchestration through one user-configured downloader, with Aria2, qBittorrent, and future compatible adapters
|
||||
- Agent-friendly CLI once v2.9 ships
|
||||
- Agent-friendly OpenAPI + Restish + upload plugin + Skill workflows once v2.9 ships
|
||||
- Desktop sync protocol foundation once v2.10 ships; actual native clients live in separate projects
|
||||
- All 7 deployment targets
|
||||
|
||||
|
||||
@@ -0,0 +1,574 @@
|
||||
# Agent Authentication and Authorization — Design
|
||||
|
||||
> Status: Proposed (2026-07-28)
|
||||
> Scope: Agent OAuth, API keys, workspace grants, protocol-neutral
|
||||
> authorization, Restish profiles, future Agent Auth compatibility, revocation,
|
||||
> and auditing
|
||||
|
||||
## 1. Decision
|
||||
|
||||
ZPan distinguishes delegated user access from unattended service access:
|
||||
|
||||
| Actor | Authorization flow | Runtime credential |
|
||||
|-------|--------------------|--------------------|
|
||||
| Interactive Agent, local callback | Authorization code + PKCE | OAuth access/refresh tokens |
|
||||
| CI or unattended service | Manual issuance | Workspace-scoped Agent API key |
|
||||
|
||||
This follows the current FlareAuth Restish v2 design: standard OpenAPI OAuth
|
||||
metadata and `x-cli-config` let Restish connect, authorize, cache, refresh, and
|
||||
revoke local tokens without a custom authorization script.
|
||||
|
||||
Standard Agent device authorization is deferred to v2.9.x. The existing
|
||||
`zpan-cli` device flow remains a narrowly scoped compatibility bootstrap for
|
||||
downloader registration and does not manufacture an Agent API key or a general
|
||||
OAuth grant.
|
||||
|
||||
Anonymous upload and preview-and-claim are explicitly excluded. Every Agent file
|
||||
operation belongs to an existing user-authorized workspace from the beginning.
|
||||
|
||||
OAuth and API keys are v2.9 credential adapters, not the file API's identity
|
||||
model. Both resolve to a protocol-neutral principal, scope set, fixed workspace,
|
||||
and audit actor. A future Agent Auth verifier plugs into that same boundary.
|
||||
|
||||
## 2. Why OAuth for Interactive Agents
|
||||
|
||||
Interactive Agents act on behalf of a signed-in human. OAuth gives that
|
||||
relationship first-class semantics:
|
||||
|
||||
- short-lived access tokens
|
||||
- refresh-token rotation and revocation
|
||||
- explicit client identity
|
||||
- explicit resource scopes
|
||||
- browser consent
|
||||
- authorization code + PKCE for public native clients
|
||||
- no browser-cookie or raw-token copy/paste
|
||||
|
||||
Restish v2 natively supports authorization code + PKCE. It caches OAuth tokens
|
||||
separately from HTTP responses, refreshes them, retries once after a `401`, and
|
||||
supports explicit logout.
|
||||
|
||||
## 3. Why API Keys Still Exist
|
||||
|
||||
CI and unattended services are different: no human is present to complete
|
||||
consent or periodically reauthorize. The existing Better Auth API-key
|
||||
foundation already supplies:
|
||||
|
||||
- hashed credential storage
|
||||
- named and independently revocable keys
|
||||
- expiry and enabled state
|
||||
- rate-limit state
|
||||
- resource/action permissions
|
||||
- workspace scope in metadata
|
||||
- owning user reference
|
||||
- per-key audit attribution
|
||||
|
||||
An Agent API key is therefore the pragmatic v2.9 service credential. It is
|
||||
created manually and stored in a CI secret. Future workload identity federation
|
||||
can replace it without changing the canonical scope and policy model.
|
||||
|
||||
## 4. Stable Upgrade Boundary
|
||||
|
||||
ZPan separates four concepts:
|
||||
|
||||
| Concept | Responsibility |
|
||||
|---------|----------------|
|
||||
| Credential adapter | Validate OAuth, API key, or future Agent JWT |
|
||||
| Principal | Identify the authorizing user, credential actor, and fixed workspace |
|
||||
| Scope and policy authorization | Intersect credential scopes with current workspace authority |
|
||||
| Use case | Perform the file operation without knowing the credential protocol |
|
||||
|
||||
Conceptually, an Agent-facing principal contains:
|
||||
|
||||
```ts
|
||||
type AgentPrincipal = {
|
||||
kind: 'delegated-user' | 'service' | 'agent'
|
||||
userId: string
|
||||
orgId: string
|
||||
scopes: ReadonlySet<Scope>
|
||||
actor: {
|
||||
type: 'agent_oauth' | 'api_key' | 'agent'
|
||||
id: string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The exact TypeScript representation may remain a discriminated union, but
|
||||
routes must authorize scopes rather than require a concrete `kind`.
|
||||
Credential-specific fields remain available for diagnostics and revocation;
|
||||
they do not select business behavior.
|
||||
|
||||
This boundary deliberately avoids two migration traps:
|
||||
|
||||
- File routes must not treat an OAuth bearer as an unrestricted browser user.
|
||||
- Agent API keys must not become ZPan's proprietary Agent identity,
|
||||
registration, signing, or capability-grant protocol.
|
||||
|
||||
With this boundary, adopting Agent Auth later adds a verifier, persistence,
|
||||
approval UI, and management UI. It does not change operation IDs, the unified
|
||||
OpenAPI document, Skill/plugin workflows, workspace authorization, or file use
|
||||
cases.
|
||||
|
||||
## 5. System-Managed OAuth Client
|
||||
|
||||
Create a built-in public native application such as `zpan-agent`.
|
||||
|
||||
Properties:
|
||||
|
||||
- system-managed and not editable/deletable
|
||||
- public client; no client secret
|
||||
- authorization code grant with PKCE
|
||||
- loopback redirect URI such as `http://localhost:8484/callback`
|
||||
- refresh-token support through `offline_access`
|
||||
- Agent scopes only
|
||||
|
||||
Dynamic client registration is not required in v2.9. One first-party client is
|
||||
enough for the versioned ZPan Skill and Restish integration.
|
||||
|
||||
The authorization server publishes discovery metadata. Clients must discover
|
||||
authorization, token, revocation, and user-info or introspection endpoints
|
||||
rather than hard-code them.
|
||||
|
||||
## 6. Workspace Grant
|
||||
|
||||
OAuth scopes describe allowed operation classes, but a ZPan grant also needs a
|
||||
resource boundary: exactly one workspace.
|
||||
|
||||
The consent record binds:
|
||||
|
||||
- authorization/grant ID
|
||||
- user ID
|
||||
- OAuth client ID
|
||||
- workspace `orgId`
|
||||
- approved scopes
|
||||
- created, expiry, revoked, and last-used state
|
||||
|
||||
Access/refresh tokens resolve to that grant. The API does not derive workspace
|
||||
from the user's mutable active-organization session.
|
||||
|
||||
Effective authorization is:
|
||||
|
||||
```text
|
||||
credential is valid
|
||||
AND grant/key allows the requested action
|
||||
AND request targets the bound workspace
|
||||
AND authorizing user still has the required workspace role
|
||||
```
|
||||
|
||||
For a team workspace, relevant requests recheck current membership and role.
|
||||
Removing the user or reducing their role immediately reduces Agent access.
|
||||
|
||||
For a personal workspace, authorization verifies that the organization is the
|
||||
authorizing user's personal organization. The current API-key branch in
|
||||
`requirePermission` lacks this personal-ownership fallback and must add it.
|
||||
|
||||
Request bodies and query parameters cannot override the credential's workspace.
|
||||
A mismatch is `403`, never a fallback to another active or personal workspace.
|
||||
|
||||
## 7. Scope Model
|
||||
|
||||
ZPan defines one canonical authorization vocabulary for scoped credentials.
|
||||
OAuth grants, Agent API keys, and future Agent credentials resolve to the same
|
||||
scope set. A browser cookie is a first-party, unbounded credential: it does not
|
||||
need a role-to-scope mapping, but it still passes the route's declared
|
||||
workspace, minimum-role, ownership, and resource policies. There is no
|
||||
separately named permission vocabulary and no `Scope -> Permission` mapping.
|
||||
|
||||
Scope names follow:
|
||||
|
||||
```text
|
||||
<resource>:<action>
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- lowercase ASCII only;
|
||||
- plural domain resource names such as `objects`, `shares`, and `tasks`;
|
||||
- a small shared action vocabulary such as `read`, `create`, `update`, and
|
||||
`delete`;
|
||||
- business operations rather than HTTP methods;
|
||||
- no wildcard semantics or access implied by string prefixes;
|
||||
- no `zpan:` prefix, because token issuer and audience already identify the
|
||||
ZPan API;
|
||||
- published scope meanings are stable and must never silently broaden.
|
||||
|
||||
Initial Agent-grantable scopes are:
|
||||
|
||||
| Scope | Intended operations |
|
||||
|-------|---------------------|
|
||||
| `objects:read` | List, inspect, and download objects |
|
||||
| `objects:create` | Create folders, upload drafts, upload-part signatures, and complete uploads |
|
||||
| `objects:update` | Rename, move, and copy objects within the authorized workspace |
|
||||
| `objects:delete` | Soft-delete objects |
|
||||
| `shares:read` | List and inspect shares |
|
||||
| `shares:create` | Create public shares |
|
||||
| `shares:delete` | Revoke shares |
|
||||
| `quota:read` | Inspect workspace quota |
|
||||
| `tasks:read` | Inspect task state |
|
||||
|
||||
Protocol scopes such as `openid` and `offline_access` retain their standard
|
||||
OAuth/OIDC meaning. They are not ZPan route permissions.
|
||||
|
||||
Every protected route declares the minimum scopes required to perform its
|
||||
operation. It does not enumerate the roles, presets, credential types, broad
|
||||
scopes, or Agent classes allowed to call it. For example:
|
||||
|
||||
```ts
|
||||
auth: {
|
||||
allOf: ['objects:delete'],
|
||||
workspace: 'required',
|
||||
}
|
||||
```
|
||||
|
||||
Scope authorization is necessary but not sufficient. Workspace membership,
|
||||
resource ownership, resource state, quota, and other request-specific
|
||||
constraints remain explicit policy checks.
|
||||
|
||||
The consent and API-key UIs can present Reader, File manager, and Publisher
|
||||
shortcuts. A shortcut expands to an explicit set of scopes; it is not itself a
|
||||
scope, and routes never reference its name. Destructive and public-sharing
|
||||
scopes remain separately selectable.
|
||||
|
||||
No Agent-grantable scope implies admin, billing, entitlement, membership,
|
||||
credential management, WebDAV, image-hosting configuration, or downloader
|
||||
registration. Those protected APIs still use the same route scope mechanism but
|
||||
are excluded from the Agent credential grant policy.
|
||||
|
||||
## 8. Authorization Code + PKCE
|
||||
|
||||
This is the default Restish flow:
|
||||
|
||||
1. Skill identifies and confirms the ZPan origin and Restish API name.
|
||||
2. Skill requires Restish v2.
|
||||
3. `restish api connect` discovers `/api/openapi.json` and applies its
|
||||
server-published OAuth binding.
|
||||
4. The first safe Agent operation starts browser authorization.
|
||||
5. Restish creates a PKCE verifier/challenge and listens on its loopback
|
||||
callback.
|
||||
6. User signs in, selects one workspace, reviews scopes, and approves or denies.
|
||||
7. Restish exchanges the authorization code and caches the tokens.
|
||||
8. Later commands refresh tokens without exposing them to the Agent response.
|
||||
|
||||
The consent page displays the Agent client, instance hostname, workspace,
|
||||
requested scopes, destructive/public side effects, and grant lifetime.
|
||||
|
||||
Restish's `--rsh-no-browser` may be used when a browser cannot be opened but the
|
||||
authorization-code callback can still be completed manually.
|
||||
|
||||
## 9. Deferred Agent Device Authorization
|
||||
|
||||
Standard Agent device authorization is a v2.9.x follow-up. It must issue tokens
|
||||
for the same workspace grant and scope model as authorization code + PKCE, not a
|
||||
broad Better Auth session token. The existing Better Auth device plugin remains
|
||||
restricted to the legacy `zpan-cli` downloader bootstrap until that follow-up.
|
||||
|
||||
## 10. Agent API-Key Issuance
|
||||
|
||||
Manual API-key creation is the initial CI path:
|
||||
|
||||
1. User opens Agent Access settings.
|
||||
2. User selects a workspace.
|
||||
3. User names the Agent or environment.
|
||||
4. User selects permissions and expiry.
|
||||
5. Server verifies current authority and creates an `agent` API key.
|
||||
6. The plaintext key is shown once.
|
||||
|
||||
New Agent keys never use `scope.mode = "user-workspaces"`. One key authorizes one
|
||||
workspace. Expiry is required, defaults to 90 days, and cannot exceed one year.
|
||||
Use one key per CI environment.
|
||||
|
||||
The UI lists name, workspace, permission summary, creation, expiry, last use,
|
||||
and status. Revocation is immediate. Rotation creates a new key and never
|
||||
reveals or mutates the old secret.
|
||||
|
||||
## 11. OpenAPI and Restish v2 Binding
|
||||
|
||||
ZPan publishes one unified `/api/openapi.json`. It defines:
|
||||
|
||||
- relative server URL for Agent API routes
|
||||
- OAuth authorization-code security scheme with Agent scopes
|
||||
- Bearer alternative for Agent API keys
|
||||
- stable operation IDs and structured errors
|
||||
- document-level Restish v2 `x-cli-config` profiles
|
||||
|
||||
Conceptual configuration:
|
||||
|
||||
```yaml
|
||||
components:
|
||||
securitySchemes:
|
||||
agentOAuth2:
|
||||
type: oauth2
|
||||
flows:
|
||||
authorizationCode:
|
||||
authorizationUrl: /api/auth/oauth2/authorize
|
||||
tokenUrl: /api/auth/oauth2/token
|
||||
scopes:
|
||||
objects:read: Read files and folders
|
||||
objects:create: Upload files and create folders
|
||||
objects:update: Rename, move, and copy files and folders
|
||||
objects:delete: Delete files and folders
|
||||
agentApiKey:
|
||||
type: http
|
||||
scheme: bearer
|
||||
|
||||
x-cli-config:
|
||||
profiles:
|
||||
default:
|
||||
credentials:
|
||||
agentOAuth2:
|
||||
params:
|
||||
client_id: zpan-agent
|
||||
scopes: openid offline_access objects:read quota:read
|
||||
redirect_path: /callback
|
||||
file-manager:
|
||||
credentials:
|
||||
agentOAuth2:
|
||||
params:
|
||||
client_id: zpan-agent
|
||||
scopes: openid offline_access objects:read objects:create objects:update objects:delete quota:read tasks:read
|
||||
redirect_path: /callback
|
||||
```
|
||||
|
||||
The real document also provides a Publisher shortcut. Reader is the default, so
|
||||
connecting the API does not silently request write or share permission. These
|
||||
profile names only expand to explicit scopes; routes never reference them.
|
||||
|
||||
A separate environment-backed profile selects `agentApiKey` for CI. No Agent
|
||||
device-code profile is published in v2.9.
|
||||
|
||||
The OpenAPI document never contains credentials or configures an executable
|
||||
credential helper. Skill instructions select a named Restish profile rather
|
||||
than assuming OAuth or a particular environment-variable name. This keeps
|
||||
operation workflows unchanged if a future local profile uses an Agent Auth
|
||||
signer.
|
||||
|
||||
All formal API operations remain visible to Restish CLI generation. Declared
|
||||
scopes and dynamic policy decide whether a credential may call them. Only
|
||||
browser callbacks and internal-only endpoints are hidden from CLI generation.
|
||||
MCP additionally ignores authentication, administration, and credential
|
||||
management operations and keeps write tools disabled by default. ZPan does not
|
||||
maintain a second Agent operation allowlist.
|
||||
|
||||
## 12. Restish Upload Plugin
|
||||
|
||||
`restish-zpan` is a Restish v2 command plugin shipped from this repository. It
|
||||
contributes `restish zpan-upload` and is installed with:
|
||||
|
||||
```sh
|
||||
restish plugin install saltbo/zpan zpan
|
||||
```
|
||||
|
||||
The plugin uses Restish delegated HTTP for ZPan draft, part re-sign, complete,
|
||||
and abort operations, preserving the selected profile, OAuth/API-key
|
||||
authentication, TLS, and normalized output. It streams local file sections
|
||||
directly to presigned S3 URLs with bounded concurrency, retry, ETag capture,
|
||||
resume checkpoints, and idempotent completion.
|
||||
|
||||
The plugin never asks Restish for authentication secrets. Checkpoints contain
|
||||
only safe API/profile identity, upload session and file identity, and completed
|
||||
part/ETag state; they contain no token, cookie, API key, or presigned URL. The
|
||||
Skill invokes this command and never implements multipart state itself.
|
||||
|
||||
## 13. Route Authorization
|
||||
|
||||
Both credential types enter a shared Agent authorization boundary.
|
||||
|
||||
For OAuth:
|
||||
|
||||
1. validate/introspect the access token;
|
||||
2. require the built-in Agent client ID and the route's required scopes;
|
||||
3. resolve user and fixed workspace grant;
|
||||
4. recheck current workspace authority.
|
||||
|
||||
For API keys:
|
||||
|
||||
1. verify key, expiry, revocation, rate limit, and owner status;
|
||||
2. require `configId = "agent"` and the route's required scopes;
|
||||
3. resolve fixed workspace metadata;
|
||||
4. recheck current workspace authority.
|
||||
|
||||
Both then invoke the same use case with the fixed `orgId` and a typed audit
|
||||
actor. Routes use shared permission middleware instead of session-only or
|
||||
principal-specific checks. The shared middleware accepts the internal principal
|
||||
contract, so tests for protected operations do not need to know how the
|
||||
principal authenticated.
|
||||
|
||||
Special considerations:
|
||||
|
||||
- A presigned upload URL may remain usable briefly after credential revocation
|
||||
because S3 validates the signature independently. Keep presigned lifetimes
|
||||
short.
|
||||
- Upload completion and new part presigning always reauthorize.
|
||||
- Issuing a new download URL requires object-read permission.
|
||||
- Listing and task responses remain workspace-filtered and paginated.
|
||||
- Share creation requires `shares:create` even when the Agent can read the
|
||||
object.
|
||||
|
||||
## 14. Audit and Management
|
||||
|
||||
Audit records distinguish resource ownership from the actor that initiated the
|
||||
operation. OAuth actions record an `agent_oauth` actor with grant/client
|
||||
attribution. API-key actions retain `api_key` with the key ID as `actorRef`.
|
||||
Both record the authorizing user, workspace, action, target, outcome, and safe
|
||||
metadata. A future Agent Auth adapter records `agent` with its Agent ID while
|
||||
retaining the delegated user as resource owner.
|
||||
|
||||
Agent Access settings show two sections:
|
||||
|
||||
- delegated OAuth grants, with client, workspace, scopes, last use, and revoke;
|
||||
- service API keys, with name, workspace, permissions, expiry, last use, and
|
||||
revoke/replace.
|
||||
|
||||
Revoking a delegated grant invalidates its refresh tokens and prevents new
|
||||
access tokens. Short access-token lifetime bounds any validation-cache delay.
|
||||
`restish api auth logout` clears local cached tokens; server-side revoke remains
|
||||
available when a device is lost.
|
||||
|
||||
Credentials are never recorded or redisplayed.
|
||||
|
||||
## 15. Current Code Gaps
|
||||
|
||||
- ZPan has bearer sessions and device authorization but is not yet an OAuth
|
||||
authorization server with Agent resource scopes and workspace grants.
|
||||
- Device authorization validates only `zpan-cli` and currently yields a
|
||||
user-oriented bearer token.
|
||||
- `shared/api-key-templates.ts` lacks an Agent template.
|
||||
- `server/http/objects.ts` rejects ordinary API-key principals.
|
||||
- authenticated shares, quota, trash, and several task routes require a user
|
||||
session instead of a permission.
|
||||
- the current principal model and `requireAuth` helper encourage routes to
|
||||
branch on identity kind; all protected routes need shared scope declarations
|
||||
and a protocol-neutral authorization boundary.
|
||||
- API-key authorization needs the personal-workspace ownership check.
|
||||
- the unified OpenAPI document lacks operation security and CLI/MCP annotations;
|
||||
- the current upload contract lacks explicit part descriptors, robust re-sign,
|
||||
expiry, idempotent completion, and a Restish command plugin.
|
||||
|
||||
These authorization-boundary changes require integration tests for OAuth and
|
||||
API-key success, missing scope/permission, wrong workspace, wrong client, role
|
||||
reduction, expiry, revocation, and personal/team spaces.
|
||||
|
||||
## 16. Agent Auth Protocol Compatibility
|
||||
|
||||
The [Agent Auth Protocol](https://agentauthprotocol.com/) is a strong long-term
|
||||
fit because it gives every Agent a cryptographic identity, scoped capability
|
||||
grants, an independent lifecycle, and per-Agent audit attribution. The
|
||||
[Better Auth Agent Auth plugin](https://better-auth.com/docs/plugins/agent-auth)
|
||||
also provides discovery, device/CIBA approval, short-lived signed JWTs, replay
|
||||
protection, OpenAPI/MCP adapters, and lifecycle events.
|
||||
|
||||
It is not the required v2.9 production path:
|
||||
|
||||
- the protocol is currently `v1.0-draft`, and the plugin documentation marks
|
||||
the implementation as unstable;
|
||||
- Restish does not natively implement Agent Auth request signing;
|
||||
- production Cloudflare Workers need distributed JTI replay storage rather than
|
||||
the plugin's default in-memory cache;
|
||||
- custom REST `location` handlers must validate grants and constraints in the
|
||||
shared authorization layer;
|
||||
- converting the full ZPan OpenAPI document into capabilities would expose too
|
||||
much surface.
|
||||
|
||||
The intended future adapter is:
|
||||
|
||||
```text
|
||||
Agent Auth JWT
|
||||
-> verify signature, audience, expiry, and JTI
|
||||
-> resolve delegated user and approved workspace
|
||||
-> normalize capability grants to the canonical Scope set
|
||||
-> create protocol-neutral principal and `agent` audit actor
|
||||
-> run existing scope and policy middleware and use case
|
||||
```
|
||||
|
||||
The effective permission remains:
|
||||
|
||||
```text
|
||||
Agent Auth capability grant
|
||||
AND authorizing user's current workspace role
|
||||
AND request targets the approved workspace
|
||||
AND resource-specific policy allows the operation
|
||||
```
|
||||
|
||||
Expected change surface:
|
||||
|
||||
| Remains unchanged | Added for Agent Auth |
|
||||
|-------------------|----------------------|
|
||||
| Unified OpenAPI and operation IDs | Agent/host/grant/approval persistence |
|
||||
| ZPan Skill and upload-plugin workflows | Agent JWT credential adapter |
|
||||
| File, share, quota, and task use cases | Approval and Agent-management UI |
|
||||
| Route scope requirements and workspace policies | Distributed JTI replay storage |
|
||||
| Presigned direct-to-S3 upload sequence | Restish signing profile/helper |
|
||||
|
||||
Agent Auth does not replace role, quota, storage, share, or ownership checks.
|
||||
Autonomous/anonymous Agent registration and later claim are outside the current
|
||||
product boundary; an initial integration supports delegated Agents only.
|
||||
|
||||
Restish remains the operation client. Until it supports Agent Auth natively, a
|
||||
future profile may use its
|
||||
[external-tool authentication](https://rest.sh/docs/recipes/use-external-tool-auth/)
|
||||
to invoke the official Agent Auth client or a minimal reviewed signer. This is
|
||||
an authentication adapter, not a standalone ZPan CLI. The unified OpenAPI
|
||||
operations and Skill workflows remain unchanged.
|
||||
|
||||
Before promotion from preview to the default interactive flow, require:
|
||||
|
||||
- a maintained Restish signing integration or native Agent Auth support;
|
||||
- distributed JTI replay protection on Workers and an equivalent Node path;
|
||||
- cross-runtime tests for registration, approval, execution, replay, revoke,
|
||||
role reduction, and workspace isolation;
|
||||
- an explicit Agent-grantable scope catalog rather than automatic authorization
|
||||
for every operation in the unified OpenAPI document;
|
||||
- acceptable upstream protocol and package stability.
|
||||
|
||||
## 17. Rejected Alternatives
|
||||
|
||||
### Device Approval Mints an API Key
|
||||
|
||||
Rejected because device approval must eventually issue the same delegated OAuth
|
||||
grant as authorization code + PKCE. Minting an API key would replace that
|
||||
short-lived and refreshable lifecycle with a proprietary exchange.
|
||||
|
||||
### API Key for Every Agent
|
||||
|
||||
Rejected because interactive user delegation benefits from consent, short access
|
||||
tokens, refresh-token revocation, and client identity. API keys remain
|
||||
appropriate for CI and unattended services.
|
||||
|
||||
### OAuth for CI by Pretending a User Is Present
|
||||
|
||||
Rejected because unattended automation should not depend on a human refresh
|
||||
grant. Use a scoped API key until workload identity federation is available.
|
||||
|
||||
### Agent Auth as the Only v2.9 Credential
|
||||
|
||||
Deferred because the protocol and current plugin remain unstable and Restish
|
||||
needs an external signer. The compatibility boundary is included now;
|
||||
production adoption can follow without making v2.9 depend on a draft protocol.
|
||||
|
||||
### Browser Cookies
|
||||
|
||||
Rejected because they are broad, mutable user-session credentials and unsafe to
|
||||
copy into Agent environments.
|
||||
|
||||
### One Credential Across All User Workspaces
|
||||
|
||||
Rejected because it makes compromise impact, audit interpretation, role changes,
|
||||
and revocation unnecessarily broad.
|
||||
|
||||
### Anonymous Upload and Claim
|
||||
|
||||
Deferred outside v2.9. File storage normally implies persistence and an
|
||||
accountable quota owner. Revisit only if ZPan deliberately builds a
|
||||
try-before-login artifact-delivery product.
|
||||
|
||||
## 18. Future Evolution
|
||||
|
||||
- Better Auth Agent Auth compatibility adapter, initially behind a feature flag
|
||||
- Delegated Agent approval and per-Agent revoke/management UI
|
||||
- Distributed JTI and Agent-key cache storage for Cloudflare Workers
|
||||
- Workload identity federation for supported CI providers
|
||||
- Dynamic client registration for trusted third-party Agent platforms
|
||||
- Standard Agent device authorization using the same workspace grant and scopes
|
||||
- Rich Authorization Requests if third-party clients need standardized
|
||||
workspace selection in the authorization request
|
||||
- HTTP Message Signatures / Web Bot Auth for additional Agent-operator
|
||||
attribution, never workspace authorization
|
||||
+335
-110
@@ -1,159 +1,384 @@
|
||||
# v2.9 — Agent CLI
|
||||
# v2.9 — Agent Access
|
||||
|
||||
Ship ZPan's command-line tool as an automation client for agents, scripts, and
|
||||
CI/CD. This CLI is not the foundation for desktop sync. It is a separate client
|
||||
surface optimized for reliable command execution and machine-readable output.
|
||||
Make ZPan operable by coding agents, scripts, and CI without maintaining a
|
||||
separate ZPan CLI. v2.9 publishes a stable Agent-facing API contract and teaches
|
||||
agents to use it through Restish v2 plus a ZPan Skill.
|
||||
|
||||
The authentication decision follows the current FlareAuth + Restish v2 pattern:
|
||||
|
||||
- **Interactive Agent:** OAuth authorization code + PKCE.
|
||||
- **Unattended automation:** workspace-scoped Agent API key.
|
||||
|
||||
Standard Agent device authorization is deferred to v2.9.x. The existing
|
||||
`zpan-cli` device flow remains only as a compatibility bootstrap for downloader
|
||||
registration and does not issue a general Agent credential.
|
||||
|
||||
OAuth grants and API keys are separate because they represent different actors:
|
||||
delegated user access versus a service credential. An Agent never receives a
|
||||
browser cookie or an unrestricted user session. Anonymous uploads, provisional
|
||||
workspaces, and claim flows are not part of v2.9.
|
||||
|
||||
The file API does not depend on either credential format. Both flows resolve to
|
||||
a protocol-neutral principal and the same scope and workspace-policy checks. This is
|
||||
an explicit compatibility boundary for adding Agent Auth Protocol later without
|
||||
redesigning the OpenAPI operations, Skill, upload plugin, or file use cases.
|
||||
|
||||
The detailed model is in
|
||||
[Agent Authentication and Authorization](../design/agent-authentication.md).
|
||||
|
||||
## Product Boundary
|
||||
|
||||
- **Community** gets the core CLI for personal and self-hosted automation.
|
||||
- **Pro / Business** may raise API limits or expose operator-only commands when
|
||||
the underlying feature is paid-tier gated.
|
||||
- Desktop sync clients do not call this CLI as their internal engine. They use
|
||||
sync-specific APIs and OS integrations in their own client projects.
|
||||
- **Community** gets the unified OpenAPI contract, interactive OAuth, Agent API
|
||||
keys, Restish setup, the ZPan upload plugin, and the ZPan Skill.
|
||||
- **Pro / Business** may raise API and automation limits, but paid tiers do not
|
||||
gate ordinary authenticated file automation.
|
||||
- Desktop sync clients do not use Restish as their engine. They continue to use
|
||||
sync-specific APIs and OS integrations in their own projects.
|
||||
|
||||
## Why CLI Here
|
||||
## Why Restish + Skill
|
||||
|
||||
Agents and automation need stable verbs:
|
||||
Restish v2 already generates commands from OpenAPI, supports OAuth and API-key
|
||||
profiles, caches and refreshes OAuth tokens, emits machine-readable output, and
|
||||
provides retries and pagination. Its official MCP plugin can expose an API as
|
||||
tools, with write operations disabled by default.
|
||||
|
||||
- upload a file
|
||||
- list folders
|
||||
- create a folder
|
||||
- move / copy / delete objects
|
||||
- create a share link
|
||||
- download an object
|
||||
- inspect quota and task state
|
||||
ZPan therefore owns:
|
||||
|
||||
These map naturally to shell commands with JSON output. They do not require a
|
||||
filesystem-provider integration, long-running sync daemon, or platform-specific
|
||||
desktop packaging.
|
||||
- one unified OpenAPI document with operation-level scope declarations
|
||||
- server-published Restish v2 authentication bindings
|
||||
- a `restish-zpan` command plugin for streaming and resumable multipart uploads
|
||||
- a ZPan Skill that explains safe workflows and selects the right Restish surface
|
||||
- the server-side authentication and authorization contract
|
||||
|
||||
## Major Features
|
||||
The plugin is a narrow Restish extension, not a standalone ZPan CLI. Restish
|
||||
continues to own command parsing for generated API operations, profiles,
|
||||
credential storage, authentication, and output formatting.
|
||||
|
||||
### Command Surface
|
||||
Baseline Restish version: **v2.3 or later**. v2.3 is selected because it includes
|
||||
the current plugin system, OAuth flows, OpenAPI credential binding, and official
|
||||
MCP integration. Restish's embedding API can build a branded CLI, but that
|
||||
option is deliberately not used.
|
||||
|
||||
Initial command groups:
|
||||
References:
|
||||
|
||||
```sh
|
||||
zpan auth login
|
||||
zpan auth status
|
||||
zpan auth logout
|
||||
- [OpenAPI CLI integration](https://rest.sh/docs/reference/openapi-cli-integration/)
|
||||
- [Authentication](https://rest.sh/docs/guides/authentication/)
|
||||
- [Automation](https://rest.sh/docs/guides/automation/)
|
||||
- [MCP plugin](https://rest.sh/docs/plugins/mcp/)
|
||||
- [Command plugins](https://rest.sh/docs/plugins/command-plugins/)
|
||||
|
||||
zpan file ls
|
||||
zpan file upload
|
||||
zpan file download
|
||||
zpan file mkdir
|
||||
zpan file mv
|
||||
zpan file cp
|
||||
zpan file rm
|
||||
zpan file stat
|
||||
## Deliverables
|
||||
|
||||
zpan share create
|
||||
zpan share list
|
||||
zpan share revoke
|
||||
### Protocol-Neutral Authorization Boundary
|
||||
|
||||
zpan space list
|
||||
zpan space use
|
||||
zpan quota get
|
||||
zpan task list
|
||||
zpan task watch
|
||||
Authentication adapters resolve credentials into an internal principal before
|
||||
any file, share, quota, or task authorization:
|
||||
|
||||
```text
|
||||
Browser session ────┐
|
||||
OAuth access token ─┼─> principal + actor + granted scopes ─> scope + policy check
|
||||
Agent API key ──────┘
|
||||
```
|
||||
|
||||
Command names should be predictable and script-friendly. Prefer explicit flags
|
||||
over interactive prompts, with optional prompts only for humans running the tool
|
||||
manually.
|
||||
Every protected route declares the minimum scopes required for its operation,
|
||||
such as `objects:read`, `objects:create`, and `shares:create`. Routes do not
|
||||
declare which credential types, roles, presets, or Agent classes may call them.
|
||||
Authentication adapters normalize browser sessions, OAuth tokens, API keys, and
|
||||
future Agent credentials into the same authorization context. Each adapter
|
||||
supplies:
|
||||
|
||||
### Agent-Friendly Output
|
||||
- the authorizing `userId`
|
||||
- the applicable workspace boundary, including one fixed `orgId` for Agent
|
||||
grants and Agent API keys
|
||||
- the granted scopes
|
||||
- a typed actor for audit attribution
|
||||
- credential expiry and revocation state
|
||||
|
||||
The CLI must be easy for coding agents and MCP-style tools to call.
|
||||
Effective permission is always the intersection of granted scopes, the
|
||||
authorizing user's current workspace role, and resource-specific rules. Adding
|
||||
a future `agent-jwt` adapter must therefore require no changes to route scope
|
||||
requirements, file use cases, or operation IDs.
|
||||
|
||||
- `--json` for every command that returns data
|
||||
- Stable exit codes
|
||||
- Errors printed as structured JSON when `--json` is active
|
||||
- No progress bars in non-TTY mode
|
||||
- `--quiet` and `--no-color`
|
||||
- Idempotency keys for commands that create or mutate resources where useful
|
||||
- Clear stderr/stdout separation
|
||||
### Unified OpenAPI
|
||||
|
||||
### Authentication
|
||||
Publish only `/api/openapi.json`. Every formal operation remains available to
|
||||
Restish command generation; declared scopes and dynamic policy determine
|
||||
whether a credential may invoke it. Browser callbacks and internal-only
|
||||
endpoints are excluded from CLI generation. MCP additionally ignores
|
||||
authentication, administration, and credential-management operations and keeps
|
||||
write tools disabled by default.
|
||||
|
||||
Supported auth paths:
|
||||
Every protected operation declares its scope and workspace/role policy at the
|
||||
route. The same declaration drives runtime enforcement and OpenAPI security, so
|
||||
there is no second Agent operation allowlist to drift. Every machine-facing
|
||||
operation needs a stable `operationId`, bounded pagination, documented
|
||||
idempotency, structured errors, and suitable examples.
|
||||
|
||||
- Personal API key for simple automation
|
||||
- Device authorization flow for human bootstrap
|
||||
- Environment variable token for CI/agent runtime use
|
||||
- Config profiles for multiple ZPan instances
|
||||
The document declares both allowed authentication alternatives:
|
||||
|
||||
The CLI should never ask users to paste browser cookies.
|
||||
- OAuth 2.0 authorization code with PKCE and Agent resource scopes
|
||||
- HTTP Bearer authentication for a manually issued Agent API key
|
||||
|
||||
### Upload And File Management
|
||||
It also publishes Restish v2 Reader, File manager, and Publisher convenience
|
||||
profiles for the built-in public native client. These names expand to explicit
|
||||
scope sets and are never referenced by routes. Reader is the default; broader
|
||||
profiles request their scopes explicitly. No secret is embedded in the
|
||||
document.
|
||||
|
||||
The CLI should use the same object upload flow as the browser:
|
||||
The existing document currently exposes roughly 145 operation IDs without
|
||||
operation security or `x-mcp-ignore` annotations. v2.9 adds those declarations
|
||||
without creating `/api/openapi.agent.json`.
|
||||
|
||||
1. Ask ZPan to create an upload draft and presigned instructions.
|
||||
2. Upload bytes directly to object storage.
|
||||
3. Complete the upload through ZPan.
|
||||
### ZPan Skill
|
||||
|
||||
It should support:
|
||||
Publish a versioned Skill that:
|
||||
|
||||
- single-file upload
|
||||
- recursive directory upload as an explicit command mode
|
||||
- conflict strategies: fail, keep both, replace
|
||||
- target space and folder selection
|
||||
- resumable multipart upload where the server already supports it
|
||||
1. detects the ZPan origin;
|
||||
2. verifies Restish v2 and connects `/api/openapi.json` with
|
||||
`--replace --yes`;
|
||||
3. selects the least-privilege Reader, File manager, or Publisher profile;
|
||||
4. syncs a previously connected API before use;
|
||||
5. triggers browser OAuth on the first safe request when a local callback is
|
||||
available;
|
||||
6. verifies and, after explicit trust confirmation, installs the
|
||||
`restish-zpan` plugin;
|
||||
7. uses an environment-backed Agent API-key profile for CI;
|
||||
8. sends every local file upload through `restish zpan-upload`;
|
||||
9. confirms target workspace, destructive operations, overwrite behavior, and
|
||||
public sharing;
|
||||
10. returns object IDs, URLs, quota effects, and task state in a compact
|
||||
machine-readable result.
|
||||
|
||||
This is file management automation, not backup/sync semantics. Local deletions
|
||||
must not imply remote deletions unless the user runs an explicit delete command.
|
||||
The Skill never asks the user to paste a bearer token. Restish owns OAuth token
|
||||
storage, refresh, logout, and redacted authentication diagnostics. Skill
|
||||
workflows refer to a selected ZPan Restish profile rather than assuming a
|
||||
specific environment variable or credential type, so a future profile may use
|
||||
an external Agent Auth signer without changing the file-operation instructions.
|
||||
|
||||
### Packaging
|
||||
### Restish Upload Plugin
|
||||
|
||||
The implementation language should be chosen during task planning. The product
|
||||
contract is more important than the runtime.
|
||||
Ship `restish-zpan` from this repository and install it with:
|
||||
|
||||
Packaging requirements:
|
||||
```sh
|
||||
restish plugin install saltbo/zpan zpan
|
||||
```
|
||||
|
||||
- macOS, Linux, Windows
|
||||
- installable in CI
|
||||
- easy for agents to locate and execute
|
||||
- versioned independently enough that agent tooling can pin a known CLI version
|
||||
It contributes `restish zpan-upload`. The plugin uses Restish delegated HTTP
|
||||
for ZPan draft, re-sign, complete, and abort operations, preserving the selected
|
||||
profile, OAuth/API-key authentication, TLS, and output behavior. It streams
|
||||
local file parts directly to presigned S3 URLs with bounded concurrency, retry,
|
||||
ETag capture, resume checkpoints, and idempotent completion. File bytes and
|
||||
presigned URLs never pass through the Agent context or Restish's plugin CBOR
|
||||
channel.
|
||||
|
||||
If implemented in this repository, keep the CLI isolated from the web frontend
|
||||
and server runtime so it does not complicate normal ZPan deployment.
|
||||
The first release supports single and multipart files, re-signing expired
|
||||
parts, interrupted resume, and explicit abort. Checkpoints contain no
|
||||
credentials or presigned URLs and are removed after success. The Skill invokes
|
||||
the plugin; it does not implement the upload state machine itself.
|
||||
|
||||
### OpenAPI Contract
|
||||
The official `restish-mcp` plugin is an optional transport for ordinary API
|
||||
operations, not the upload implementation. Its default read-only mode is useful
|
||||
for browsing. Enable write tools only with an explicit operation allowlist:
|
||||
|
||||
The CLI should use the public REST/OpenAPI surface, not private frontend helpers.
|
||||
If an existing route is awkward for CLI use, improve the API contract rather than
|
||||
special-casing the CLI.
|
||||
```sh
|
||||
restish plugin install rest-sh/restish mcp
|
||||
restish mcp serve zpan --allow-write-tools \
|
||||
--operations listObjects,getObject,createObject,completeObjectUpload
|
||||
```
|
||||
|
||||
Frontend code continues to use Hono RPC wrappers.
|
||||
Keep MCP results bounded; the plugin's default result limit is 16 KiB. Object
|
||||
contents continue to move through presigned URLs, never through an MCP result.
|
||||
|
||||
### Interactive OAuth
|
||||
|
||||
Create a system-managed public native client, for example `zpan-agent`, with:
|
||||
|
||||
- authorization code + PKCE
|
||||
- loopback callback such as `http://localhost:8484/callback`
|
||||
- refresh-token support through `offline_access`
|
||||
- only Agent API scopes
|
||||
|
||||
The default Restish profile uses authorization code + PKCE. After
|
||||
`restish api connect`, the first safe Agent API request opens browser consent;
|
||||
Restish caches and refreshes the resulting tokens. `--rsh-no-browser` may be
|
||||
used when the callback can still be completed manually. Standard Agent device
|
||||
authorization remains a v2.9.x follow-up.
|
||||
|
||||
Consent binds the grant to:
|
||||
|
||||
- the signed-in user
|
||||
- exactly one workspace
|
||||
- requested resource scopes
|
||||
- the user's current workspace role
|
||||
- the OAuth client and expiry/revocation state
|
||||
|
||||
Access tokens are short-lived. Refresh tokens remain bounded by that grant.
|
||||
Changing team membership or revoking the grant removes access independently of
|
||||
the user's browser sessions.
|
||||
|
||||
### Agent API Keys
|
||||
|
||||
Add an `agent` API-key template for CI and other unattended automation.
|
||||
|
||||
Defaults:
|
||||
|
||||
- exactly one workspace
|
||||
- least-privilege permissions selected by the user
|
||||
- explicit name, expiry, last-used time, and revocation
|
||||
- separate keys for separate Agents and environments
|
||||
- no admin, billing, membership, entitlement, or credential-management access
|
||||
- team membership and role rechecked at authorization boundaries
|
||||
- rate and storage limits enforced server-side
|
||||
|
||||
The plaintext key is returned once and stored in a CI secret or another
|
||||
non-interactive secret store.
|
||||
|
||||
### Scopes and Presets
|
||||
|
||||
The server has one canonical authorization vocabulary. OAuth grants, API keys,
|
||||
browser-session roles, and future Agent credentials all produce a set of the
|
||||
same scopes; there is no separate `Scope -> Permission` mapping.
|
||||
|
||||
Scope names use the stable, lowercase `<resource>:<action>` form. Resources are
|
||||
plural domain nouns and actions come from a small shared vocabulary such as
|
||||
`read`, `create`, `update`, and `delete`. Scope names describe business
|
||||
authority, not HTTP methods. They do not include a redundant `zpan:` prefix:
|
||||
the token issuer and audience already identify the ZPan API.
|
||||
|
||||
Initial Agent-grantable scopes are:
|
||||
|
||||
| Scope | Intended operations |
|
||||
|-------|---------------------|
|
||||
| `objects:read` | List, inspect, and download objects |
|
||||
| `objects:create` | Upload files and create folders |
|
||||
| `objects:update` | Rename, move, and copy objects |
|
||||
| `objects:delete` | Soft-delete objects |
|
||||
| `shares:read` | List and inspect shares |
|
||||
| `shares:create` | Create public shares |
|
||||
| `shares:delete` | Revoke shares |
|
||||
| `quota:read` | Inspect workspace quota |
|
||||
| `tasks:read` | Inspect task state |
|
||||
|
||||
Protocol scopes such as `openid` and `offline_access` retain their standard
|
||||
OAuth/OIDC meaning. They are not ZPan route permissions.
|
||||
|
||||
Each protected route declares its minimum required scopes. A route declares
|
||||
what authority the operation needs, not a list of broad scopes or caller types
|
||||
that are allowed to invoke it. Workspace membership, resource ownership,
|
||||
resource state, quota, and other dynamic constraints remain policy checks after
|
||||
the scope check.
|
||||
|
||||
Reader, File manager, and Publisher are UI/Restish shortcuts that expand to
|
||||
explicit scope sets. They are not scopes and routes never reference preset names.
|
||||
Destructive and public-sharing scopes remain separately selectable.
|
||||
|
||||
## Current Gaps to Close
|
||||
|
||||
- ZPan is not currently an OAuth authorization server for Agent resource
|
||||
scopes.
|
||||
- The existing device authorization plugin returns a user-oriented bearer token
|
||||
and validates only the legacy `zpan-cli` client ID.
|
||||
- Object routes currently reject ordinary API-key principals with a blanket
|
||||
session-only gate.
|
||||
- Authenticated share and quota routes currently require a user session.
|
||||
- Protected routes need shared scope middleware that accepts a protocol-neutral
|
||||
principal instead of branching on `user`, `api-key`, or another credential
|
||||
kind. Every protected route must declare its minimum scopes.
|
||||
- API-key templates currently cover image hosting, WebDAV, and remote download,
|
||||
but not general Agent file management.
|
||||
- Workspace API-key authorization needs an explicit personal-space ownership
|
||||
path in addition to team membership checks.
|
||||
- The unified OpenAPI document lacks operation security and CLI/MCP annotations.
|
||||
- Upload conflict policy, idempotency, and multipart retry behavior need an
|
||||
explicit public contract.
|
||||
|
||||
## Delivery Order
|
||||
|
||||
1. Define the canonical scope vocabulary and scope declaration metadata.
|
||||
2. Refactor all protected routes to authorize protocol-neutral principals,
|
||||
declare minimum scopes, and emit typed actors rather than require a
|
||||
particular principal kind.
|
||||
3. Add manual Agent API keys and make scoped API access work end to end.
|
||||
4. Add the system-managed public native OAuth client, Agent grants, and
|
||||
authorization-code + PKCE flow.
|
||||
5. Stabilize the server multipart protocol.
|
||||
6. Publish unified OpenAPI security and Restish v2 credential bindings.
|
||||
7. Ship and release the `restish-zpan` upload command plugin.
|
||||
8. Ship the ZPan Skill and validate browser OAuth and CI profiles.
|
||||
9. Add the optional, allowlisted Restish MCP recipe.
|
||||
|
||||
API keys come first as the smallest way to prove the resource authorization
|
||||
boundary. They do not become the interactive login protocol.
|
||||
|
||||
## Non-goals for v2.9
|
||||
|
||||
- Desktop sync engine
|
||||
- Apple File Provider, Windows Cloud Files, Linux filesystem integration
|
||||
- Flutter, Tauri, Swift, Kotlin, or other graphical clients
|
||||
- Bidirectional sync or conflict replication
|
||||
- Enterprise / legacy identity protocols such as LDAP, SCIM, or SAML
|
||||
- Folder-level ACLs or custom roles
|
||||
- A standalone `zpan` CLI or branded Restish binary
|
||||
- Standard Agent device authorization before the v2.9.x follow-up
|
||||
- Anonymous upload, provisional workspace, preview-and-claim, or anonymous
|
||||
permanent storage
|
||||
- Desktop sync or filesystem-provider integration
|
||||
- Agent access to admin, billing, entitlement, membership, or credential
|
||||
management
|
||||
- Giving an Agent a browser cookie or unrestricted user session
|
||||
- Dynamic third-party OAuth client registration
|
||||
- Making the draft Agent Auth Protocol or its current Better Auth plugin a
|
||||
required production dependency
|
||||
- A ZPan-specific Agent identity, key-signing, capability-grant, or claim
|
||||
protocol that duplicates a future standards-based integration
|
||||
- Enterprise identity protocols or custom workspace roles
|
||||
- Server-proxied file bytes
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- A Restish v2 client connects to `/api/openapi.json`, triggers browser
|
||||
OAuth + PKCE, and reuses/refreshes cached tokens without token copy/paste.
|
||||
- Consent shows and binds one workspace and the requested scopes.
|
||||
- A CI job can use a manually created workspace-scoped Agent API key.
|
||||
- Browser-session, OAuth, and API-key principals pass through the same scope and
|
||||
workspace-policy authorization.
|
||||
- Every protected route declares its minimum required scopes; no route
|
||||
authorizes by credential kind, Agent type, or preset name.
|
||||
- Agent-facing routes and use cases do not branch on OAuth versus API key, and
|
||||
their authorization tests can supply a protocol-neutral principal directly.
|
||||
- Attempts to access another workspace or an ungranted operation return `403`
|
||||
and produce an audit event.
|
||||
- Removing the grant/key owner's team membership or reducing their role
|
||||
immediately removes the corresponding Agent access.
|
||||
- Expired or revoked credentials cannot complete uploads or issue new download
|
||||
URLs.
|
||||
- The unified OpenAPI document derives operation security from route declarations.
|
||||
- `restish zpan-upload` completes and resumes multipart uploads without exposing
|
||||
file bytes, credentials, or presigned URLs to the Agent.
|
||||
- Credentials never enter logs, audit metadata, analytics, share URLs, or MCP
|
||||
results.
|
||||
|
||||
## User Scenarios
|
||||
|
||||
**Coding agent:**
|
||||
> The agent uploads a generated artifact, creates a share link, and posts the
|
||||
> link back to the user without needing browser automation.
|
||||
**Interactive coding Agent:**
|
||||
> The Agent connects ZPan through Restish. My browser opens a consent screen
|
||||
> where I approve one workspace and the requested scopes. Restish stores and
|
||||
> refreshes the OAuth tokens locally.
|
||||
|
||||
**CI release workflow:**
|
||||
> A GitHub Actions job uploads build artifacts to ZPan and creates a stable share
|
||||
> link for release notes.
|
||||
|
||||
**Power user:**
|
||||
> I run `zpan file upload ./dist --target /releases/v2.9 --recursive --json` and
|
||||
> get a machine-readable summary of uploaded files and share URLs.
|
||||
> I create a File manager API key for the release workspace, store it as a CI
|
||||
> secret, and rotate it independently of my user sessions.
|
||||
|
||||
## Future Work
|
||||
|
||||
- MCP server wrapping the CLI or using the same OpenAPI client
|
||||
- Admin/operator command groups for Business features
|
||||
- Bulk migration helpers
|
||||
- Shell completions and package-manager distribution polish
|
||||
- Evaluate the Better Auth Agent Auth plugin as an optional compatibility layer
|
||||
once its draft protocol and packages are stable enough for production. Map its
|
||||
short-lived Agent JWTs and capability grants into the same principal,
|
||||
workspace, and scope-and-policy boundary defined in v2.9.
|
||||
- Keep Restish as the operation transport. Until Restish supports Agent Auth
|
||||
natively, use its reviewed `external-tool` authentication hook with the
|
||||
official Agent Auth client/signing helper; do not build a standalone ZPan CLI.
|
||||
- Before enabling Agent Auth on Cloudflare Workers, provide distributed JTI
|
||||
replay storage and validate revocation across Worker isolates.
|
||||
- Dynamic client registration for trusted third-party Agent platforms
|
||||
- Workload identity federation for CI providers to remove stored long-lived
|
||||
secrets
|
||||
- HTTP Message Signatures / Web Bot Auth as an additional Agent-operator
|
||||
authentication signal, never as file authorization by itself
|
||||
- First-party remote MCP server if Restish's local MCP transport proves
|
||||
insufficient
|
||||
- Standard Agent device authorization with the same workspace grant and scopes
|
||||
|
||||
Reference in New Issue
Block a user