Skip to content
Draft
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
16 changes: 16 additions & 0 deletions docs/en/docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ Server settings use the `POWERCONTEXT_SERVER_` prefix.
| `POWERCONTEXT_SERVER_MCP_PATH` | `/mcp` | MCP path |
| `POWERCONTEXT_SERVER_AUTH_ENABLED` | `false` | Require one static bearer token for HTTP and MCP |
| `POWERCONTEXT_SERVER_AUTH_TOKEN` | unset | Static bearer token; required when authentication is enabled |
| `POWERCONTEXT_SERVER_ACCESS_MODE` | `legacy-static-admin` | Authorization rollout: `disabled`, `legacy-static-admin`, or `enforced` |
| `POWERCONTEXT_SERVER_ACCESS_BOOTSTRAP_STATIC_PRINCIPAL` | `true` | Treat the deployment-local static-token Principal as a bootstrap Server administrator |
| `POWERCONTEXT_SERVER_ALLOW_UNAUTHENTICATED_NON_LOOPBACK` | `false` | Opt in to a non-loopback bind while authentication is disabled |
| `POWERCONTEXT_SERVER_DASHBOARD_ENABLED` | `true` | Enable the Dashboard at the Server root path `/` |
| `POWERCONTEXT_SERVER_DASHBOARD_SCOPES` | `[]` | JSON array of selectable Dashboard scopes |
Expand Down Expand Up @@ -93,6 +95,20 @@ when TLS is terminated upstream or the network is otherwise controlled, set
`POWERCONTEXT_SERVER_ALLOW_UNAUTHENTICATED_NON_LOOPBACK=true` to opt in explicitly. Use TLS before exposing an
authenticated Server over a network.

Authentication establishes a Principal; Access Control decides what that Principal may do. The built-in static token
always represents one deployment-local service Principal, so it cannot distinguish user A from user B. The default
`legacy-static-admin` mode maps that Principal to a bootstrap Server administrator and preserves the single-user local
deployment. `enforced` enables the same policy enforcement point and persistent Binding/audit store for an injected
multi-user authentication and Authorization Provider. Set `bootstrap_static_principal=false` after another
administrator relationship is available. `disabled` bypasses authorization decisions and is intended only for an
explicit compatibility rollback inside an already trusted network boundary.

The built-in Access schema uses the configured SQLite, seekDB, or OceanBase backend, but remains Server-owned rather
than becoming a Runtime domain. A custom deployment can inject an `AccessControlService` into `create_server_app` and
implement the `AuthorizationProvider` and `RelationshipWriter` protocols with OpenFGA, Casbin, Oso, or another policy
system. Its authentication middleware must bind an opaque `PrincipalRef`; `scope_id` is only a resource partition and
never establishes identity.

The Python Client and CLI apply the matching rule for outbound requests: a configured unencrypted `http://` Server
URL is accepted only for loopback hosts. The Client refuses to send any request, authenticated or not, over
unencrypted non-loopback HTTP. Code whose `http://` base URL is only a routing label for a transport that is secure in
Expand Down
38 changes: 38 additions & 0 deletions docs/en/docs/reference/http-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,48 @@ curl --fail \
"$POWERCONTEXT_URL/v1/memory/search"
```

## Grant one exact Handoff to a receiver

`scope_id` never grants access by itself. An administrator delegates one exact committed Handoff by creating a
Binding for the receiver's authenticated Principal:

```bash
curl --fail \
--request POST \
--header 'Content-Type: application/json' \
--header "$POWERCONTEXT_AUTH_HEADER" \
--data '{
"subject": {"type": "user", "issuer": "https://id.example", "id": "user-b"},
"resource": {
"type": "handoff",
"scope_id": "project:example",
"family": "handoff",
"artifact_id": "handoff-42",
"revision": 3
},
"role": "handoff.receiver",
"idempotency_key": "handoff-42-r3-to-user-b"
}' \
"$POWERCONTEXT_URL/v1/access/bindings/create"
```

The receiver can read evidence and acknowledge only that Revision. It cannot use latest-Handoff discovery, read
another Handoff, or access Memory in the parent scope unless a separate scope role allows it. Use `/v1/access/me` to
verify which Principal the deployment established, `/v1/access/check` for one decision, and
`/v1/access/resources/list` for a non-discovering list of already visible resources. Creation is idempotent per
grantor and key; revocation uses `binding_id` plus `expected_version`. Relationship and decision events are available
to Server administrators through `/v1/access/audit/list`.

The built-in static token represents one local administrator and cannot model different A/B users. A real multi-user
deployment must authenticate each caller to a different Principal and inject an Authorization Provider. HTTP and MCP
use the same policy enforcement point; MCP tool visibility is not permission.

## Find an operation

| Area | Main paths | Purpose |
| --- | --- | --- |
| Health and capabilities | `/health/*`, `/v1/capabilities` | Probe the deployment and discover enabled runtime behavior |
| Access Control | `/v1/access/*` | Inspect identity, check decisions, and administer roles, Bindings, and audit events |
| Source and context | `/v1/sources/content`, `/v1/context/prepare` | Capture evidence and prepare bounded context |
| Work continuity | `/v1/work/*` | Create work contracts, prepare or acknowledge Handoffs, and record outcomes |
| Low-level Handoff | `/v1/handoff/*` | Activate, prepare, finalize, commit, or continue a Handoff |
Expand Down Expand Up @@ -127,6 +164,7 @@ Common statuses are:
| Status | Meaning |
| --- | --- |
| `401` | The Server requires a valid bearer token |
| `403` | The authenticated Principal is not authorized for the requested action and resource |
| `404` | The requested immutable value does not exist |
| `409` | The request conflicts with current immutable state or an expected version |
| `413` | A selected Handoff Report exceeds its output limit |
Expand Down
13 changes: 13 additions & 0 deletions docs/zh/docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ Server 配置使用 `POWERCONTEXT_SERVER_` 前缀。
| `POWERCONTEXT_SERVER_MCP_PATH` | `/mcp` | MCP 路径 |
| `POWERCONTEXT_SERVER_AUTH_ENABLED` | `false` | HTTP 和 MCP 是否要求一个静态 Bearer token |
| `POWERCONTEXT_SERVER_AUTH_TOKEN` | 未设置 | 静态 Bearer token;启用鉴权时必须设置 |
| `POWERCONTEXT_SERVER_ACCESS_MODE` | `legacy-static-admin` | 权限启用模式:`disabled`、`legacy-static-admin` 或 `enforced` |
| `POWERCONTEXT_SERVER_ACCESS_BOOTSTRAP_STATIC_PRINCIPAL` | `true` | 是否把部署本地静态 token 的 Principal 作为初始 Server 管理员 |
| `POWERCONTEXT_SERVER_ALLOW_UNAUTHENTICATED_NON_LOOPBACK` | `false` | 在鉴权关闭时显式允许绑定非 loopback 地址 |
| `POWERCONTEXT_SERVER_DASHBOARD_ENABLED` | `true` | 在 Server 根路径 `/` 启用 Dashboard |
| `POWERCONTEXT_SERVER_DASHBOARD_SCOPES` | `[]` | Dashboard 可选择的 scope JSON 数组 |
Expand Down Expand Up @@ -89,6 +91,17 @@ TLS 由上游终止或网络本身受控的场景下,
显式设置 `POWERCONTEXT_SERVER_ALLOW_UNAUTHENTICATED_NON_LOOPBACK=true` 主动选择接受。通过网络暴露启用鉴权的
Server 前必须配置 TLS。

Authentication 负责建立 Principal,Access Control 负责判断该 Principal 能做什么。内置静态 token 始终只代表一个
部署本地 service Principal,因此不能区分用户 A 和用户 B。默认 `legacy-static-admin` 会把该 Principal 映射为初始
Server 管理员,以保持单用户本地部署的兼容行为。`enforced` 使用同一个策略执行点和持久化 Binding/审计存储,供注入的
多用户 authentication 与 Authorization Provider 使用。在已有其他管理员关系后,可设置
`bootstrap_static_principal=false`。`disabled` 会跳过授权决策,只应作为可信网络边界内的显式兼容回退。

内置 Access schema 使用配置好的 SQLite、seekDB 或 OceanBase,但由 Server 独立持有,不进入 Runtime 领域。自定义部署
可以向 `create_server_app` 注入 `AccessControlService`,并用 OpenFGA、Casbin、Oso 或其他策略系统实现
`AuthorizationProvider` 与 `RelationshipWriter` protocol。authentication middleware 必须绑定不透明的
`PrincipalRef`;`scope_id` 只用于资源分区,不能建立身份。

Python Client 和 CLI 对出站请求应用相同规则:配置的明文 `http://` Server URL 仅接受 loopback 主机,并且 Client 拒绝
通过明文的非 loopback HTTP 发送任何请求,无论是否携带 Bearer token。当代码的 `http://` base URL 只是路由标签、
实际传输是安全的,例如进程内 ASGI 应用、Unix domain socket 或由代理终止 TLS 时,必须自行传入 `http_client` 并
Expand Down
35 changes: 35 additions & 0 deletions docs/zh/docs/reference/http-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,45 @@ curl --fail \
"$POWERCONTEXT_URL/v1/memory/search"
```

## 把一个精确 Handoff 授予接收者

`scope_id` 本身从不授予权限。管理员通过创建 Binding,把一个精确的 committed Handoff 授予接收者已经认证的
Principal:

```bash
curl --fail \
--request POST \
--header 'Content-Type: application/json' \
--header "$POWERCONTEXT_AUTH_HEADER" \
--data '{
"subject": {"type": "user", "issuer": "https://id.example", "id": "user-b"},
"resource": {
"type": "handoff",
"scope_id": "project:example",
"family": "handoff",
"artifact_id": "handoff-42",
"revision": 3
},
"role": "handoff.receiver",
"idempotency_key": "handoff-42-r3-to-user-b"
}' \
"$POWERCONTEXT_URL/v1/access/bindings/create"
```

接收者只能读取证据并确认这个 Revision;除非另有 scope role,否则不能发现 latest Handoff、读取其他 Handoff,
也不能访问父 scope 的 Memory。用 `/v1/access/me` 确认部署建立的 Principal,用 `/v1/access/check` 检查一个决策,
用 `/v1/access/resources/list` 非发现式地列出已经可见的资源。创建操作按授权者与幂等键保证幂等;撤销时必须提交
`binding_id` 和 `expected_version`。Server 管理员可通过 `/v1/access/audit/list` 查看关系变更与决策事件。

内置静态 token 只代表一个本地管理员,无法表达不同的 A/B 用户。真正的多用户部署必须把每个调用者认证为不同的
Principal,并注入 Authorization Provider。HTTP 与 MCP 使用同一个策略执行点;MCP tool 可见不等于有权限。

## 查找操作

| 领域 | 主要路径 | 用途 |
| --- | --- | --- |
| 健康与能力 | `/health/*`、`/v1/capabilities` | 探测部署状态并查看已启用的 Runtime 行为 |
| Access Control | `/v1/access/*` | 查看身份、检查决策,并管理 role、Binding 和审计事件 |
| Source 与 Context | `/v1/sources/content`、`/v1/context/prepare` | 采集证据并准备有界 Context |
| 工作连续性 | `/v1/work/*` | 创建 Work Contract、准备或确认 Handoff、记录 Outcome |
| 底层 Handoff | `/v1/handoff/*` | activate、prepare、finalize、commit 或 continue Handoff |
Expand Down Expand Up @@ -120,6 +154,7 @@ curl --fail \
| 状态码 | 含义 |
| --- | --- |
| `401` | Server 要求有效的 Bearer token |
| `403` | 已认证 Principal 无权对目标资源执行请求的 action |
| `404` | 请求的不可变值不存在 |
| `409` | 请求与当前不可变状态或 expected version 冲突 |
| `413` | 选中的 Handoff Report 超过输出限制 |
Expand Down
54 changes: 54 additions & 0 deletions integrations/dsh/plugins/powercontext/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,60 @@ const OPERATIONS = {
path: "/v1/handoff-reports/workspace-bindings/detach",
location: "body",
scope: false
},
get_access_principal: {
method: "GET",
path: "/v1/access/me",
location: null,
scope: false
},
check_access: {
method: "POST",
path: "/v1/access/check",
location: "body",
scope: false
},
check_access_batch: {
method: "POST",
path: "/v1/access/check-batch",
location: "body",
scope: false
},
list_access_resources: {
method: "POST",
path: "/v1/access/resources/list",
location: "body",
scope: false
},
list_access_roles: {
method: "POST",
path: "/v1/access/roles/list",
location: "body",
scope: false
},
list_access_bindings: {
method: "POST",
path: "/v1/access/bindings/list",
location: "body",
scope: false
},
create_access_binding: {
method: "POST",
path: "/v1/access/bindings/create",
location: "body",
scope: false
},
revoke_access_binding: {
method: "POST",
path: "/v1/access/bindings/revoke",
location: "body",
scope: false
},
list_access_audit: {
method: "POST",
path: "/v1/access/audit/list",
location: "body",
scope: false
}
};
const OPERATION_IDS = Object.keys(OPERATIONS);
Expand Down
Loading
Loading