@piagent/platform 1.1.5 → 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +1 -1
- package/adapters/be-readonly-fe/profile.json +12 -4
- package/docs/capability-packs.md +21 -0
- package/docs/command-reference-vietnamese.md +2 -2
- package/docs/distribution-standard.md +7 -7
- package/docs/operator-manual-vietnamese.md +7 -7
- package/docs/project-adapters.md +44 -0
- package/docs/publishing-for-teams.md +2 -0
- package/docs/release-install-policy.md +6 -6
- package/docs/security-threat-model.md +1 -1
- package/docs/team-onboarding.md +3 -3
- package/docs-site/index.html +2 -2
- package/package.json +1 -1
- package/packages/piagent-core/capabilities/capability-core.js +109 -8
- package/packages/piagent-core/capabilities/project-profile.js +83 -0
- package/packages/piagent-core/extensions/piagent-guard.ts +97 -95
- package/packages/piagent-core/extensions/project-shape.js +285 -0
- package/packages/piagent-core/package.json +1 -1
- package/schemas/project-profile.schema.json +25 -7
- package/scripts/capability-catalog.mjs +28 -7
- package/scripts/init-project.sh +19 -89
- package/scripts/install-global.sh +3 -3
- package/scripts/profile-doctor.sh +13 -3
- package/scripts/runtime-policy-smoke.sh +12 -3
- package/scripts/team-doctor.sh +12 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
This file records release-facing changes for Pi Agent Platform. Copy the relevant version block into GitHub Releases when publishing a tag.
|
|
4
4
|
|
|
5
|
+
## v1.1.7 - 2026-07-28
|
|
6
|
+
|
|
7
|
+
A platform update is one global install. It was not behaving like one: every project that selected capability packs stopped working after a release until its profile was reapplied by hand, and the policy a release corrected never reached a project that had already onboarded.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- A capability lock that is behind the installed platform is re-pinned instead of refusing the session. The lock pinned two different things and gave them one answer. What the project consented to — which packs, from where, and how far they may reach — still blocks: a grant that widens, a protection that disappears, a pack that changes identity. Which build produced the resolution — package version, runtime file digests, artifact content — moves on every release, and blocking on it put a per-project chore behind a global update while not defending against the case it resembles, since the code that verifies the lock is itself one of the files the lock pins. A build move with an unchanged grant is recorded and reported.
|
|
12
|
+
|
|
13
|
+
- Artifact content is part of the build, not part of consent. Adapter policy files, base policy, prompts, skills, subagents and recipes all ship as pack artifacts, so pinning their bytes meant a corrected policy could never reach a project referencing it. Nothing is given up: which artifacts a pack provides is declared in its manifest and the manifest digest is still pinned, so an artifact that appears, disappears or moves still blocks — and a policy artifact that weakens still blocks, because the permissions it resolves to are compared directionally.
|
|
14
|
+
|
|
15
|
+
- A project profile can name the adapter it takes its policy from instead of copying it. `{"extends": "web-frontend", "projectId": ..., "displayName": ...}` keeps the project's identity and overrides in the project, and resolves the rest from the installed platform at runtime. Any key the project states replaces the adapter's key whole; a profile without `extends` keeps working exactly as before, self-contained. `init-project.sh` and `/onboard-project` write this form when the profile comes from a built-in adapter, so onboarding stays the one per-project step and updating stays global.
|
|
16
|
+
|
|
17
|
+
A profile naming an adapter that is not installed refuses rather than falling back to something weaker.
|
|
18
|
+
|
|
19
|
+
## v1.1.6 - 2026-07-27
|
|
20
|
+
|
|
21
|
+
Monorepo fixes found auditing how the platform scopes itself to a project. Every case was reproduced against a real directory tree before it was changed.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- `be-readonly-fe` keeps the backend read-only in a monorepo. Its `readOnlyPaths` and `shellProtectedPaths` were anchored at the repository root, so `backend/**` and `apps/api/**` covered a backend sitting at the top of the tree and nothing else. Choosing the profile on a repository whose backend lives in `packages/api`, `apps/backend` or `services/payments` produced a profile that announced the backend was read-only while leaving every file in it writable — the one guarantee the profile exists to make. The backend directories under `apps/`, `packages/` and all of `services/*` are covered now.
|
|
26
|
+
|
|
27
|
+
They are enumerated rather than matched with `**/api/**`, which would have swept in `packages/web/src/api/` — the frontend's own HTTP client — and frozen the half of the repository the profile is meant to leave writable.
|
|
28
|
+
|
|
29
|
+
- The frontend verify command finds a frontend that is not at `frontend/` or `apps/web/`. It fell through to the repository root, where a workspace root has no `type-check` script, so verification reported success having run nothing. `apps/frontend`, `packages/web`, `packages/frontend` and `client` are looked at too.
|
|
30
|
+
|
|
31
|
+
- `apps/backend` is read as a backend. `apps/frontend` counted as a frontend marker while only `apps/api` and `apps/server` counted as backend ones, so a repository that named both halves symmetrically was detected as frontend-only and offered `web-frontend`. `client/` and `server/` at the root were not markers either.
|
|
32
|
+
|
|
33
|
+
- Frontend and backend are detected inside declared workspaces. Nothing read the `workspaces` field or `pnpm-workspace.yaml`, and nothing looked under `packages/`, so a pnpm monorepo fell through every marker to `generic`. Each declared package is now read through its own manifest and layout, which is what identifies `packages/storefront` and `packages/gateway` as the two halves of a fullstack repository. Only a trailing wildcard is expanded, absolute and `..` patterns are refused, and at most 64 packages are read.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- Profile detection lives in `packages/piagent-core/extensions/project-shape.js`. `piagent_profile_options` and `scripts/init-project.sh` each carried their own copy of the rules and had drifted; the `apps/backend` gap above was present in both, and a fix to either would have left the other wrong. The file is covered by the capability lock, because steering which profile a project is offered is a way to choose what the guard ends up enforcing.
|
|
38
|
+
|
|
5
39
|
## v1.1.5 - 2026-07-27
|
|
6
40
|
|
|
7
41
|
### Added
|
package/README.md
CHANGED
|
@@ -283,7 +283,7 @@ This repository intentionally excludes:
|
|
|
283
283
|
|
|
284
284
|
## Maturity
|
|
285
285
|
|
|
286
|
-
The current package version is read from package metadata and release tags. Personal machines may follow the unpinned package source when accepting ongoing updates; production/team quickstarts and committed project settings should pin an explicit tag such as `v1.1.
|
|
286
|
+
The current package version is read from package metadata and release tags. Personal machines may follow the unpinned package source when accepting ongoing updates; production/team quickstarts and committed project settings should pin an explicit tag such as `v1.1.7` or a reviewed commit.
|
|
287
287
|
|
|
288
288
|
Ready for:
|
|
289
289
|
|
|
@@ -32,7 +32,11 @@
|
|
|
32
32
|
"api/**",
|
|
33
33
|
"apps/api/**",
|
|
34
34
|
"apps/server/**",
|
|
35
|
-
"
|
|
35
|
+
"apps/backend/**",
|
|
36
|
+
"packages/api/**",
|
|
37
|
+
"packages/server/**",
|
|
38
|
+
"packages/backend/**",
|
|
39
|
+
"services/*/**",
|
|
36
40
|
"**/migrations/**"
|
|
37
41
|
],
|
|
38
42
|
"shellProtectedPaths": [
|
|
@@ -47,7 +51,11 @@
|
|
|
47
51
|
"api/**",
|
|
48
52
|
"apps/api/**",
|
|
49
53
|
"apps/server/**",
|
|
50
|
-
"
|
|
54
|
+
"apps/backend/**",
|
|
55
|
+
"packages/api/**",
|
|
56
|
+
"packages/server/**",
|
|
57
|
+
"packages/backend/**",
|
|
58
|
+
"services/*/**",
|
|
51
59
|
"**/migrations/**",
|
|
52
60
|
"**/node_modules/**",
|
|
53
61
|
"**/dist/**",
|
|
@@ -85,10 +93,10 @@
|
|
|
85
93
|
"test -s README.md"
|
|
86
94
|
],
|
|
87
95
|
"frontendSource": [
|
|
88
|
-
"if test -f frontend/package.json; then cd frontend
|
|
96
|
+
"if test -f frontend/package.json; then cd frontend; elif test -f apps/web/package.json; then cd apps/web; elif test -f apps/frontend/package.json; then cd apps/frontend; elif test -f packages/web/package.json; then cd packages/web; elif test -f packages/frontend/package.json; then cd packages/frontend; elif test -f client/package.json; then cd client; elif test -f package.json; then :; else echo 'No frontend verify command configured; update .pi/piagent-profile.json'; exit 0; fi; npm run type-check --if-present && npm run lint --if-present && npm test --if-present"
|
|
89
97
|
],
|
|
90
98
|
"frontendRuntime": [
|
|
91
|
-
"if test -f frontend/package.json; then cd frontend
|
|
99
|
+
"if test -f frontend/package.json; then cd frontend; elif test -f apps/web/package.json; then cd apps/web; elif test -f apps/frontend/package.json; then cd apps/frontend; elif test -f packages/web/package.json; then cd packages/web; elif test -f packages/frontend/package.json; then cd packages/frontend; elif test -f client/package.json; then cd client; elif test -f package.json; then :; else echo 'No frontend runtime verify command configured; update .pi/piagent-profile.json'; exit 0; fi; npm run test:e2e --if-present"
|
|
92
100
|
]
|
|
93
101
|
},
|
|
94
102
|
"mcpCapabilities": [
|
package/docs/capability-packs.md
CHANGED
|
@@ -153,6 +153,7 @@ Pack không thể cấp thêm quyền cho chính nó:
|
|
|
153
153
|
- Doctor phát hiện catalog hoặc lock stale.
|
|
154
154
|
- Generated output dùng temporary file cùng thư mục, `fsync`, rồi atomic rename.
|
|
155
155
|
- Lock gắn với declared package-source identifier, package version, catalog và digest của các runtime enforcement file đang cài. Đây là integrity binding của runtime quan sát được, không phải chứng minh nguồn gốc cryptographic của package archive.
|
|
156
|
+
- Lock drift được phân loại hai nhánh, xem `## Lock drift` bên dưới.
|
|
156
157
|
- Optional runtime package được cài bằng exact version; installer đối chiếu registry integrity với digest đã phê duyệt trước khi cài.
|
|
157
158
|
- Khi cập nhật profile, lock được ghi trước; nếu profile không thể ghi thì lock được rollback. Process interruption tạo trạng thái mismatch fail-closed thay vì áp dụng profile thiếu lock.
|
|
158
159
|
|
|
@@ -166,6 +167,26 @@ Pack không thể cấp thêm quyền cho chính nó:
|
|
|
166
167
|
- `validate-action` chỉ kiểm tra contract, thời hạn và secret indicator; không authorize action, không đối chiếu requested permission với profile/lock và không đọc artifact để xác minh digest/size.
|
|
167
168
|
- External action vẫn cần human confirmation và executor riêng trước khi có side effect.
|
|
168
169
|
|
|
170
|
+
## Lock drift
|
|
171
|
+
|
|
172
|
+
Lock pin hai thứ khác nhau, và khi lệch thì câu trả lời cũng khác nhau.
|
|
173
|
+
|
|
174
|
+
**Consent — project phải đồng ý lại, session bị chặn (`blocked`):**
|
|
175
|
+
|
|
176
|
+
- `schemaVersion` của lock, `core.apiVersion`, `core.packageSource`;
|
|
177
|
+
- `profile` — `projectId`, `mode`, tên file, digest của document project tự lưu;
|
|
178
|
+
- `packs` — name, version, origin, source, owner, lifecycle và digest của manifest. Manifest khai luôn `provides`, nên artifact xuất hiện thêm, biến mất hoặc đổi path đều nằm ở nhánh này;
|
|
179
|
+
- permission theo hướng: granting key (`capabilities`, `filesystemRead`, `filesystemWrite`, `networkDomains`, `externalActions`) chặn khi **thêm**; restricting key (`protectedPaths`, `readOnlyPaths`, `shellProtectedPaths`) chặn khi **mất**.
|
|
180
|
+
|
|
181
|
+
**Build — platform đổi bản, lock được ghi lại và báo, session chạy tiếp (`repin`):**
|
|
182
|
+
|
|
183
|
+
- `core.packageVersion`, `core.runtimeFiles`, `core.packageDigest`;
|
|
184
|
+
- nội dung artifact (`artifacts[].digest`).
|
|
185
|
+
|
|
186
|
+
Vì sao nội dung artifact nằm ở nhánh build: adapter policy file, base policy, prompt, skill, subagent và recipe đều ship dạng artifact. Pin bytes của chúng nghĩa là bản sửa policy không bao giờ tới được project đang tham chiếu — đúng thứ mà việc ship policy tập trung tồn tại để làm. Không mất gì khi bỏ pin: danh sách artifact nằm trong manifest và manifest digest vẫn được pin ở `packs`, còn policy artifact bị nới lỏng vẫn chặn vì permission sau resolve được so trực tiếp theo hướng.
|
|
187
|
+
|
|
188
|
+
Việc pin build cũng chưa bao giờ chống được trường hợp nó trông giống: code kiểm tra lock chính là một trong các file mà lock pin, nên thứ gì sửa được platform đã cài thì sửa luôn được checker.
|
|
189
|
+
|
|
169
190
|
## Lifecycle
|
|
170
191
|
|
|
171
192
|
| Trạng thái | Ý nghĩa |
|
|
@@ -419,8 +419,8 @@ Các lệnh này chạy ngoài Pi.
|
|
|
419
419
|
| Command | Dùng khi nào |
|
|
420
420
|
|---|---|
|
|
421
421
|
| `npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0` | Cài Pi CLI tương thích với release hiện tại. |
|
|
422
|
-
| `npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
423
|
-
| `pi install git:github.com/Vt-mmm/piagent@v1.1.
|
|
422
|
+
| `npm install -g --ignore-scripts @piagent/platform@1.1.7` | Cài terminal helper `piagent-*` từ release tag hiện tại. |
|
|
423
|
+
| `pi install git:github.com/Vt-mmm/piagent@v1.1.7` | Cài pinned release khi cần reproducible team setup. |
|
|
424
424
|
| `pi install git:github.com/Vt-mmm/piagent` | Cài latest package platform cho máy cá nhân/sandbox. |
|
|
425
425
|
| `piagent-update --check` | Báo version hiện tại vs version sẽ lên cho cả ba thành phần; không cài gì. |
|
|
426
426
|
| `piagent-update` | Full update một lệnh: Pi host → npm-global helper → Pi package, đúng thứ tự release yêu cầu. Thêm `--project <path>` để chạy doctor sau. |
|
|
@@ -14,9 +14,9 @@ Repo này phải chạy được cho nhiều project/domain khác nhau. Vì vậ
|
|
|
14
14
|
|
|
15
15
|
| Use case | Package source |
|
|
16
16
|
|---|---|
|
|
17
|
-
| Team pinned release | `git:github.com/Vt-mmm/piagent@v1.1.
|
|
17
|
+
| Team pinned release | `git:github.com/Vt-mmm/piagent@v1.1.7` |
|
|
18
18
|
| Personal/sandbox dev | `git:github.com/Vt-mmm/piagent` |
|
|
19
|
-
| Registry distribution | `npm:@piagent/platform@1.1.
|
|
19
|
+
| Registry distribution | `npm:@piagent/platform@1.1.7` |
|
|
20
20
|
| Enterprise npm (fork under another scope) | `npm:@your-scope/platform@x.y.z` |
|
|
21
21
|
| Local platform dev | `/path/to/piagent` |
|
|
22
22
|
|
|
@@ -26,7 +26,7 @@ Latest tiện cho máy cá nhân muốn nhận cập nhật nhanh. Pin tag/commi
|
|
|
26
26
|
|
|
27
27
|
| Channel | Command | Target | Policy |
|
|
28
28
|
|---|---|---|---|
|
|
29
|
-
| `stable` | `bash scripts/install-global.sh --stable` | Helper release tag resolved to commit SHA, currently `v1.1.
|
|
29
|
+
| `stable` | `bash scripts/install-global.sh --stable` | Helper release tag resolved to commit SHA, currently `v1.1.7` | Install the Pi package matching the helper. |
|
|
30
30
|
| `exact` | `bash scripts/install-global.sh --version vX.Y.Z --resolve-tag` | Requested tag resolved to commit SHA | Pi-package-only rollout, rollback, and incident recovery. |
|
|
31
31
|
| `dev` | `bash scripts/install-global.sh --dev` | Moving Git source | Personal/sandbox only; do not commit into project settings. |
|
|
32
32
|
| `local` | `bash scripts/install-global.sh --local` | Current checkout path | Platform development only. |
|
|
@@ -53,7 +53,7 @@ Root `package.json` có `pi` manifest trỏ tới:
|
|
|
53
53
|
Do đó team có thể:
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
|
-
pi install git:github.com/Vt-mmm/piagent@v1.1.
|
|
56
|
+
pi install git:github.com/Vt-mmm/piagent@v1.1.7
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
Không cần biết internal folder `packages/piagent-core`. Source không pin chỉ dành cho personal/sandbox như bảng channel ở trên.
|
|
@@ -65,12 +65,12 @@ Team nên install global package một lần:
|
|
|
65
65
|
```bash
|
|
66
66
|
node --version # >= 22.19.0
|
|
67
67
|
npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
|
|
68
|
-
npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
68
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.7
|
|
69
69
|
piagent-install --stable --dry-run
|
|
70
70
|
piagent-install --stable
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
`pi install git:github.com/Vt-mmm/piagent@v1.1.
|
|
73
|
+
`pi install git:github.com/Vt-mmm/piagent@v1.1.7` vẫn hợp lệ nếu chỉ cần cài Pi package. Lệnh đó không tự tạo các binary terminal `piagent-*`; muốn có helper global thì dùng `npm install -g --ignore-scripts @piagent/platform@1.1.7`.
|
|
74
74
|
|
|
75
75
|
Support matrix hiện tại: macOS Apple Silicon + Bash và Linux x64 + Bash đã được verify; macOS Intel + Bash và Linux ARM64 + Bash là supported target cần chạy smoke trước rollout; native Windows chưa phải target rollout team; WSL2 experimental. Chi tiết và version runtime nằm trong [release/install policy](release-install-policy.md).
|
|
76
76
|
|
|
@@ -103,7 +103,7 @@ Nếu muốn commit sẵn `.pi/piagent-profile.json` vào repo hoặc bootstrap
|
|
|
103
103
|
```bash
|
|
104
104
|
bash scripts/setup.sh /path/to/project \
|
|
105
105
|
--profile be-readonly-fe \
|
|
106
|
-
--package-source git:github.com/Vt-mmm/piagent@v1.1.
|
|
106
|
+
--package-source git:github.com/Vt-mmm/piagent@v1.1.7 \
|
|
107
107
|
--mcp-preset core \
|
|
108
108
|
--subagents-preset safe
|
|
109
109
|
```
|
|
@@ -18,12 +18,12 @@ Support matrix release hiện tại: macOS Apple Silicon + Bash và Linux x64 +
|
|
|
18
18
|
```bash
|
|
19
19
|
node --version # >= 22.19.0
|
|
20
20
|
npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
|
|
21
|
-
npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
21
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.7
|
|
22
22
|
piagent-install --stable --dry-run
|
|
23
23
|
piagent-install --stable
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
Khi seed `.pi/settings.json` cho team/repo cần audit lặp lại, giữ package source dạng pinned tag như `git:github.com/Vt-mmm/piagent@v1.1.
|
|
26
|
+
Khi seed `.pi/settings.json` cho team/repo cần audit lặp lại, giữ package source dạng pinned tag như `git:github.com/Vt-mmm/piagent@v1.1.7`. Máy cá nhân có thể dùng `git:github.com/Vt-mmm/piagent` để theo latest.
|
|
27
27
|
|
|
28
28
|
Nếu đang ở source checkout của platform, dùng helper theo channel để preview trước khi đổi:
|
|
29
29
|
|
|
@@ -99,7 +99,7 @@ install package once
|
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
101
|
npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
|
|
102
|
-
npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
102
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.7
|
|
103
103
|
piagent-install --stable --dry-run
|
|
104
104
|
piagent-install --stable
|
|
105
105
|
```
|
|
@@ -281,7 +281,7 @@ Không phải daily default. Dùng khi muốn tạo sẵn `.pi` files cho projec
|
|
|
281
281
|
bash /path/to/piagent/scripts/setup.sh /path/to/project \
|
|
282
282
|
--project-only \
|
|
283
283
|
--profile auto \
|
|
284
|
-
--package-source git:github.com/Vt-mmm/piagent@v1.1.
|
|
284
|
+
--package-source git:github.com/Vt-mmm/piagent@v1.1.7 \
|
|
285
285
|
--mcp-preset core \
|
|
286
286
|
--subagents-preset safe
|
|
287
287
|
```
|
|
@@ -854,8 +854,8 @@ Watchdog là optional adversarial reviewer ở cuối turn, không bật mặc
|
|
|
854
854
|
|
|
855
855
|
| Command | Dùng để |
|
|
856
856
|
|---|---|
|
|
857
|
-
| `npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
858
|
-
| `pi install git:github.com/Vt-mmm/piagent@v1.1.
|
|
857
|
+
| `npm install -g --ignore-scripts @piagent/platform@1.1.7` | Cài terminal helper `piagent-*` từ release tag hiện tại. |
|
|
858
|
+
| `pi install git:github.com/Vt-mmm/piagent@v1.1.7` | Install pinned release cho reproducible team setup. |
|
|
859
859
|
| `pi install git:github.com/Vt-mmm/piagent` | Install latest platform package cho máy cá nhân/sandbox. |
|
|
860
860
|
| Cài exact Pi host của release, rồi `npm install -g --ignore-scripts @piagent/platform@X.Y.Z` và `piagent-install --stable` | Full update: đồng bộ host, terminal helper và Pi package. Mỗi release pin một Pi host chính xác; lấy đúng version của release đang cài trong [release/install policy](release-install-policy.md). |
|
|
861
861
|
| Cài exact Pi host ghi trong release cũ, rồi helper `vPREVIOUS` và `piagent-install --stable` | Full rollback; đánh giá lại dependency findings của host cũ trước khi hạ version. |
|
|
@@ -952,7 +952,7 @@ Mở lại Pi session sau khi install.
|
|
|
952
952
|
Cài lại terminal helper đúng release rồi kiểm tra `PATH`:
|
|
953
953
|
|
|
954
954
|
```bash
|
|
955
|
-
npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
955
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.7
|
|
956
956
|
command -v piagent-install
|
|
957
957
|
```
|
|
958
958
|
|
package/docs/project-adapters.md
CHANGED
|
@@ -68,6 +68,45 @@ Path policy fields have distinct meanings:
|
|
|
68
68
|
- `readOnlyPaths`: allow `read`/`grep`/`find`/`ls`, but block `write`/`edit` and shell access.
|
|
69
69
|
- `shellProtectedPaths`: block shell access only. Do not rely on this field to block write/edit; `profile-doctor` and `team-doctor` warn when a path is present only here.
|
|
70
70
|
|
|
71
|
+
Glob trong các field này neo từ project root, nên `backend/**` chỉ khớp backend nằm ở root. Với monorepo, phải liệt kê đúng vị trí thật (`packages/api/**`, `services/*/**`). Không dùng `**/api/**`: nó khớp luôn `packages/web/src/api/` — thư mục HTTP client của frontend — và biến chính phần được phép sửa thành read-only.
|
|
72
|
+
|
|
73
|
+
## Profile theo reference (`extends`)
|
|
74
|
+
|
|
75
|
+
Profile ở trên là dạng self-contained: project ghi toàn bộ policy. Dạng này đóng băng policy tại thời điểm onboard — platform sửa adapter thì project cũ vẫn giữ bản copy cũ mãi.
|
|
76
|
+
|
|
77
|
+
`extends` biến policy thành reference. Project chỉ giữ phần thuộc về project, phần còn lại lấy từ adapter trong platform đang cài:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"schemaVersion": 1,
|
|
82
|
+
"extends": "web-frontend",
|
|
83
|
+
"projectId": "my-project",
|
|
84
|
+
"displayName": "My Project"
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Quy tắc:
|
|
89
|
+
|
|
90
|
+
- `extends` trỏ tới một thư mục trong `adapters/` của platform đang cài. Tên không tồn tại → guard refuse, không fallback im lặng.
|
|
91
|
+
- Mọi key project tự khai **thay thế nguyên key** của adapter, không merge từng phần tử. Khai `protectedPaths` nghĩa là project sở hữu list đó và không nhận thay đổi từ adapter nữa.
|
|
92
|
+
- Không khai `extends` thì profile giữ nguyên hành vi cũ, self-contained.
|
|
93
|
+
|
|
94
|
+
`scripts/init-project.sh` và `/onboard-project` ghi dạng `extends` khi profile đến từ built-in adapter. Update platform sau đó không cần chạm vào project nào.
|
|
95
|
+
|
|
96
|
+
## Monorepo và workspace
|
|
97
|
+
|
|
98
|
+
Một project = một thư mục mở `pi`. Guard đọc profile tại `<cwd>/.pi/piagent-profile.json` và không đi ngược lên tìm, nên mở `pi` ở thư mục cha chứa nhiều project sẽ bỏ qua profile của từng project con và chạy unprofiled.
|
|
99
|
+
|
|
100
|
+
Detect FE/BE đọc theo thứ tự:
|
|
101
|
+
|
|
102
|
+
1. Tên thư mục ở root: `frontend`, `web`, `client`, `ui` cho FE; `backend`, `server`, `api` cho BE.
|
|
103
|
+
2. Cùng các tên đó ở một cấp dưới `apps/`, `packages/`, `services/`.
|
|
104
|
+
3. Package khai báo trong `workspaces` (package.json, cả dạng mảng lẫn `{ "packages": [...] }`) hoặc `pnpm-workspace.yaml` — mỗi package đọc dependency và config của chính nó, nên `packages/storefront` + `packages/gateway` vẫn ra `fullstack` dù tên không gợi ý gì.
|
|
105
|
+
|
|
106
|
+
Chỉ wildcard ở segment cuối được mở rộng (`packages/*`, `apps/**`); pattern tuyệt đối, pattern có `..`, và pattern loại trừ `!` bị bỏ qua. Số package đọc tối đa 64.
|
|
107
|
+
|
|
108
|
+
Rule nằm ở `packages/piagent-core/extensions/project-shape.js`. Cả `piagent_profile_options` lẫn `scripts/init-project.sh` cùng gọi file này; trước đây mỗi bên giữ một bản riêng và đã lệch nhau.
|
|
109
|
+
|
|
71
110
|
## Built-in adapters
|
|
72
111
|
|
|
73
112
|
| Profile | Dùng cho | Verify mặc định |
|
|
@@ -84,6 +123,11 @@ Path policy fields have distinct meanings:
|
|
|
84
123
|
| `mobile` | React Native/Flutter | npm test / flutter test nếu tool có |
|
|
85
124
|
| `docs` | Docs portal/manual | markdown diff check + test nếu project có |
|
|
86
125
|
|
|
126
|
+
`be-readonly-fe` giữ read-only cho backend ở root (`backend`, `server`, `api`), ở một cấp dưới `apps/` và `packages/` (`api`, `server`, `backend`), toàn bộ `services/*`, và mọi `**/migrations/**`. Profile built-in là điểm khởi đầu, không phải danh sách đầy đủ — sửa `readOnlyPaths` **và** `shellProtectedPaths` trong `.pi/piagent-profile.json` cho đúng repo:
|
|
127
|
+
|
|
128
|
+
- backend đặt tên khác (`apps/gateway`, `packages/core-service`): thêm path vào cả hai field.
|
|
129
|
+
- frontend nằm trong `services/` (ví dụ `services/web`): `services/*/**` sẽ khoá nhầm nó. Thay pattern đó bằng danh sách service backend cụ thể. Triệu chứng là một write bị chặn kèm lý do trỏ tới `readOnlyPaths`, không phải lỗi im lặng.
|
|
130
|
+
|
|
87
131
|
## Runtime profile selection
|
|
88
132
|
|
|
89
133
|
Default UX không bắt buộc chạy bash để set profile. Sau global install, vào project chạy:
|
|
@@ -48,6 +48,8 @@ pi install /path/to/piagent
|
|
|
48
48
|
- `1.1.3`: command mang secret không còn được dùng làm verify evidence, document reader từ chối FIFO thay vì treo, redact secret ngắn, redirect phải về đúng trang được kiểm.
|
|
49
49
|
- `1.1.4`: nhận diện secret dạng CLI option (`--token`, `--password`, `--api-key`) và Authorization header ở mọi vị trí argument.
|
|
50
50
|
- `1.1.5`: thêm `piagent-update` — một lệnh update cả Pi host, terminal helper và Pi package đúng thứ tự.
|
|
51
|
+
- `1.1.6`: `be-readonly-fe` giữ được backend read-only trong monorepo, detect FE/BE đọc cả workspace, và rule detect gộp về một chỗ.
|
|
52
|
+
- `1.1.7`: update global không còn chặn project đang chạy — lock chỉ block khi grant thật sự đổi, và profile dạng `extends` nhận policy từ platform đang cài thay vì giữ bản copy lúc onboard.
|
|
51
53
|
|
|
52
54
|
## Không publish
|
|
53
55
|
|
|
@@ -10,7 +10,7 @@ This file is the canonical install, update, rollback, and release checklist. Oth
|
|
|
10
10
|
|
|
11
11
|
All supported environments require Node.js `>=22.19.0` and Pi Coding Agent `0.82.0`. The Pi host is installed as a Node CLI; Pi Agent Platform still defines its own release matrix because the terminal helpers and shell policy rely on Bash/POSIX behavior.
|
|
12
12
|
|
|
13
|
-
| Surface | Status for v1.1.
|
|
13
|
+
| Surface | Status for v1.1.7 | Rollout guidance |
|
|
14
14
|
|---|---|---|
|
|
15
15
|
| macOS Apple Silicon (`darwin/arm64`) + Bash | Verified for this release. | Safe default for team rollout after normal project smoke tests. |
|
|
16
16
|
| Linux x64 + Bash | Verified in GitHub Actions. | Safe default for CI/server usage after normal project smoke tests. |
|
|
@@ -33,7 +33,7 @@ These three components are versioned independently. A full install, update, or r
|
|
|
33
33
|
|
|
34
34
|
| Channel | Source shape | Mutability | Use when |
|
|
35
35
|
|---|---|---:|---|
|
|
36
|
-
| `stable` | `git:github.com/Vt-mmm/piagent@<resolved-commit-sha>` from `v1.1.
|
|
36
|
+
| `stable` | `git:github.com/Vt-mmm/piagent@<resolved-commit-sha>` from `v1.1.7` | Fixed after resolution | Default for team rollout. |
|
|
37
37
|
| `exact` | Tag, reviewed commit, or a tag resolved with `--resolve-tag` | Fixed when using a commit SHA | Pi-package-only roll forward, rollback, or reproduction. |
|
|
38
38
|
| `dev` | `git:github.com/Vt-mmm/piagent` | Moving | Personal machine or sandbox only. |
|
|
39
39
|
| `local` | `/path/to/piagent` | Local workspace | Platform development and dry-run validation. |
|
|
@@ -53,7 +53,7 @@ Use this flow when the team needs both terminal commands and the Pi package:
|
|
|
53
53
|
```bash
|
|
54
54
|
node --version # >= 22.19.0
|
|
55
55
|
npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
|
|
56
|
-
npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
56
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.7
|
|
57
57
|
piagent-install --stable --dry-run
|
|
58
58
|
piagent-install --stable
|
|
59
59
|
```
|
|
@@ -61,8 +61,8 @@ piagent-install --stable
|
|
|
61
61
|
The stable preview and apply output includes:
|
|
62
62
|
|
|
63
63
|
```text
|
|
64
|
-
currentRelease: v1.1.
|
|
65
|
-
tag: v1.1.
|
|
64
|
+
currentRelease: v1.1.7 (helper package version)
|
|
65
|
+
tag: v1.1.7
|
|
66
66
|
resolvedCommit: <40-char-sha>
|
|
67
67
|
source: git:github.com/Vt-mmm/piagent@<40-char-sha>
|
|
68
68
|
```
|
|
@@ -79,7 +79,7 @@ bash scripts/install-global.sh --stable
|
|
|
79
79
|
Use this only when terminal commands are not needed:
|
|
80
80
|
|
|
81
81
|
```bash
|
|
82
|
-
pi install git:github.com/Vt-mmm/piagent@v1.1.
|
|
82
|
+
pi install git:github.com/Vt-mmm/piagent@v1.1.7
|
|
83
83
|
```
|
|
84
84
|
|
|
85
85
|
Direct `pi install` does not create `piagent-*` commands on `PATH`.
|
|
@@ -21,7 +21,7 @@ This document covers the packaged guard, project profiles, capability locks, ins
|
|
|
21
21
|
- The operator, operating-system account, Pi host, and explicitly trusted project repository are trusted to execute code.
|
|
22
22
|
- Project-local Pi resources are loaded only after Pi project trust or an explicit operator override.
|
|
23
23
|
- A human remains available to approve destructive and external-provider actions.
|
|
24
|
-
- Supported release verification covers macOS Apple Silicon + Bash, Linux x64 + Bash, Node.js `>=22.19.0`, and the exact Pi host version declared by the release. macOS Intel + Bash and Linux ARM64 + Bash are supported targets that need local smoke verification before broad rollout. Native Windows is not a team-rollout target for v1.1.
|
|
24
|
+
- Supported release verification covers macOS Apple Silicon + Bash, Linux x64 + Bash, Node.js `>=22.19.0`, and the exact Pi host version declared by the release. macOS Intel + Bash and Linux ARM64 + Bash are supported targets that need local smoke verification before broad rollout. Native Windows is not a team-rollout target for v1.1.7, and WSL2 is experimental/unverified.
|
|
25
25
|
- Registry, GitHub, model-provider, MCP-provider, and Vercel controls are external dependencies. Their account security and platform guarantees are not replaced by this repository.
|
|
26
26
|
|
|
27
27
|
## Threat actors and failure modes
|
package/docs/team-onboarding.md
CHANGED
|
@@ -9,7 +9,7 @@ Một thành viên mới không cần biết local path của maintainer. Luồn
|
|
|
9
9
|
```bash
|
|
10
10
|
node --version # >= 22.19.0
|
|
11
11
|
npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
|
|
12
|
-
npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
12
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.7
|
|
13
13
|
piagent-install --stable
|
|
14
14
|
cd /path/to/project
|
|
15
15
|
pi
|
|
@@ -42,7 +42,7 @@ Mặc định team dùng stable helper:
|
|
|
42
42
|
```bash
|
|
43
43
|
node --version # >= 22.19.0
|
|
44
44
|
npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
|
|
45
|
-
npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
45
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.7
|
|
46
46
|
piagent-install --stable --dry-run
|
|
47
47
|
piagent-install --stable
|
|
48
48
|
```
|
|
@@ -70,7 +70,7 @@ piagent-update --check
|
|
|
70
70
|
piagent-update --project /path/to/project
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
`--check` chỉ báo version, không đụng gì. Lên đúng một bản cụ thể thì `piagent-update --version 1.1.
|
|
73
|
+
`--check` chỉ báo version, không đụng gì. Lên đúng một bản cụ thể thì `piagent-update --version 1.1.7`.
|
|
74
74
|
|
|
75
75
|
Sequence thủ công vẫn dùng được, và bắt buộc theo thứ tự này — `piagent-install` **fail** nếu Pi host lệch bản pin, nó không tự nâng host:
|
|
76
76
|
|
package/docs-site/index.html
CHANGED
|
@@ -798,7 +798,7 @@
|
|
|
798
798
|
<span>Pi Agent Platform</span>
|
|
799
799
|
</a>
|
|
800
800
|
<div class="top-actions">
|
|
801
|
-
<span class="pill"><span class="pill-dot"></span>v1.1.
|
|
801
|
+
<span class="pill"><span class="pill-dot"></span>v1.1.7 docs</span>
|
|
802
802
|
<a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
|
|
803
803
|
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
|
804
804
|
<path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
|
@@ -934,7 +934,7 @@
|
|
|
934
934
|
<article class="step">
|
|
935
935
|
<div>
|
|
936
936
|
<h3>Cài — hai lệnh</h3>
|
|
937
|
-
<p>Cần Node.js 22.19.0 trở lên. Không cần cài Pi Coding Agent trước: <span class="inline-code">piagent-setup</span> tự cài đúng bản <span class="inline-code">0.82.0</span> mà release <span class="inline-code">v1.1.
|
|
937
|
+
<p>Cần Node.js 22.19.0 trở lên. Không cần cài Pi Coding Agent trước: <span class="inline-code">piagent-setup</span> tự cài đúng bản <span class="inline-code">0.82.0</span> mà release <span class="inline-code">v1.1.7</span> đang pin. Chạy nó ngay trong thư mục project — nó cài Pi package, khởi tạo <span class="inline-code">.pi/</span>, cài MCP baseline cùng subagents, rồi chạy doctor. Thêm <span class="inline-code">--no-mcp</span>, <span class="inline-code">--no-subagents</span>, <span class="inline-code">--no-herdr</span> hoặc <span class="inline-code">--global-only</span> để bỏ bớt.</p>
|
|
938
938
|
<div class="table-wrap compact-table">
|
|
939
939
|
<table>
|
|
940
940
|
<thead>
|
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { containsSensitiveText } from "../security/sensitive-data.js";
|
|
5
|
+
import { resolveProjectProfileDocument } from "./project-profile.js";
|
|
5
6
|
|
|
6
7
|
const API_VERSION = "piagent/v1";
|
|
7
8
|
const CORE_API_VERSION = 1;
|
|
@@ -785,6 +786,9 @@ function buildCoreIntegrity(root) {
|
|
|
785
786
|
// capability-sources.js decides which external trees become readable packs,
|
|
786
787
|
// so tampering with it changes which code the profile can grant.
|
|
787
788
|
"packages/piagent-core/capabilities/capability-sources.js",
|
|
789
|
+
// project-profile.js decides which document is enforced when a project takes
|
|
790
|
+
// its policy from an adapter, so it selects the protected paths themselves.
|
|
791
|
+
"packages/piagent-core/capabilities/project-profile.js",
|
|
788
792
|
"packages/piagent-core/security/sensitive-data.js",
|
|
789
793
|
"packages/piagent-core/extensions/piagent-guard.ts",
|
|
790
794
|
// guard-io.js loads the project profile and guard-shell-analysis.ts decides
|
|
@@ -795,7 +799,11 @@ function buildCoreIntegrity(root) {
|
|
|
795
799
|
"packages/piagent-core/extensions/guard-shell-analysis.ts",
|
|
796
800
|
"packages/piagent-core/extensions/policy-core.js",
|
|
797
801
|
"packages/piagent-core/extensions/redaction-core.js",
|
|
798
|
-
"packages/piagent-core/extensions/runtime-evidence.js"
|
|
802
|
+
"packages/piagent-core/extensions/runtime-evidence.js",
|
|
803
|
+
// project-shape.js picks the profile a project is offered, and the profile is
|
|
804
|
+
// the document that carries protectedPaths and readOnlyPaths. Steering the
|
|
805
|
+
// recommendation is a way to choose what the guard will end up enforcing.
|
|
806
|
+
"packages/piagent-core/extensions/project-shape.js"
|
|
799
807
|
];
|
|
800
808
|
return files.map((relativePath) => {
|
|
801
809
|
const resolved = resolveRegularFile(root, relativePath, MAX_ARTIFACT_BYTES);
|
|
@@ -900,7 +908,7 @@ export function resolveCapabilityProfileDocument(root, profile, options = {}) {
|
|
|
900
908
|
projectId: profile.projectId,
|
|
901
909
|
mode: profile.mode,
|
|
902
910
|
file: profileFile,
|
|
903
|
-
digest: sha256(stableJson(profile))
|
|
911
|
+
digest: sha256(stableJson(options.storedProfile ?? profile))
|
|
904
912
|
},
|
|
905
913
|
packs: [...selected.values()].map((pack) => ({
|
|
906
914
|
name: pack.name,
|
|
@@ -923,25 +931,118 @@ export function resolveCapabilityProfileDocument(root, profile, options = {}) {
|
|
|
923
931
|
|
|
924
932
|
export function resolveCapabilityProfile(root, profilePath, options = {}) {
|
|
925
933
|
const profileAbsolute = fs.realpathSync(profilePath);
|
|
926
|
-
const
|
|
934
|
+
const stored = readJsonFile(profileAbsolute);
|
|
935
|
+
const { profile } = resolveProjectProfileDocument(fs.realpathSync(root), stored);
|
|
927
936
|
return resolveCapabilityProfileDocument(root, profile, {
|
|
928
937
|
profileFile: path.basename(profileAbsolute),
|
|
938
|
+
// The lock records the document the project owns. A profile that takes its
|
|
939
|
+
// policy from an adapter is meant to follow that adapter, so digesting the
|
|
940
|
+
// resolved document instead would turn every platform correction into a
|
|
941
|
+
// lock the project has to re-agree to by hand.
|
|
942
|
+
storedProfile: stored,
|
|
929
943
|
packageSource: options.packageSource,
|
|
930
944
|
extraRoots: options.extraRoots
|
|
931
945
|
});
|
|
932
946
|
}
|
|
933
947
|
|
|
948
|
+
// A lock pins two different things and they deserve different answers when they
|
|
949
|
+
// stop matching.
|
|
950
|
+
//
|
|
951
|
+
// What the project consented to: which packs, from where, and how far they may
|
|
952
|
+
// reach. Granting more than that, or covering less than that, is a change the
|
|
953
|
+
// project has to agree to, so it blocks.
|
|
954
|
+
//
|
|
955
|
+
// Which build of the platform produced the resolution: its version, the digests
|
|
956
|
+
// of its runtime files, and the content of the artifacts its packs ship. That
|
|
957
|
+
// moves on every release. Blocking on it put a per-project chore behind a global
|
|
958
|
+
// update — every project on a profile that selects packs stopped working until
|
|
959
|
+
// its profile was reapplied — while not actually defending against the case it
|
|
960
|
+
// resembles: the code that verifies the lock is itself one of the files the lock
|
|
961
|
+
// pins, so anything able to rewrite the installed platform can rewrite the check
|
|
962
|
+
// along with it. A build move with an unchanged grant is re-pinned and reported,
|
|
963
|
+
// not refused.
|
|
964
|
+
//
|
|
965
|
+
// Artifact content sits on the build side deliberately. Adapter policy files,
|
|
966
|
+
// base policy, prompts, skills, subagents, and recipes all ship as artifacts, so
|
|
967
|
+
// pinning their bytes means a policy correction cannot reach a project that
|
|
968
|
+
// references it — which is the whole point of shipping policy centrally. Nothing
|
|
969
|
+
// is given up by that: which artifacts a pack provides is declared in its
|
|
970
|
+
// manifest, and the manifest digest is pinned in `packs`, so an artifact that
|
|
971
|
+
// appears, disappears, or moves still blocks. A policy artifact that weakens
|
|
972
|
+
// blocks too, because the permissions it resolves to are compared directly
|
|
973
|
+
// below.
|
|
974
|
+
const GRANTING_PERMISSIONS = ["capabilities", "filesystemRead", "filesystemWrite", "networkDomains", "externalActions"];
|
|
975
|
+
const RESTRICTING_PERMISSIONS = ["protectedPaths", "readOnlyPaths", "shellProtectedPaths"];
|
|
976
|
+
|
|
977
|
+
function consentedShape(document) {
|
|
978
|
+
return {
|
|
979
|
+
schemaVersion: document?.schemaVersion,
|
|
980
|
+
apiVersion: document?.core?.apiVersion,
|
|
981
|
+
packageSource: document?.core?.packageSource,
|
|
982
|
+
profile: document?.profile,
|
|
983
|
+
packs: document?.packs
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
function consentDrift(expected, actual) {
|
|
988
|
+
const before = consentedShape(actual);
|
|
989
|
+
const after = consentedShape(expected);
|
|
990
|
+
return Object.keys(after)
|
|
991
|
+
.filter((key) => stableJson(after[key]) !== stableJson(before[key]))
|
|
992
|
+
.map((key) => `${key} no longer matches the locked value`);
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
function permissionDrift(expected, actual) {
|
|
996
|
+
const locked = actual?.permissions ?? {};
|
|
997
|
+
const resolved = expected?.permissions ?? {};
|
|
998
|
+
const drift = [];
|
|
999
|
+
|
|
1000
|
+
for (const key of GRANTING_PERMISSIONS) {
|
|
1001
|
+
const agreed = new Set(locked[key] ?? []);
|
|
1002
|
+
const added = (resolved[key] ?? []).filter((item) => !agreed.has(item));
|
|
1003
|
+
if (added.length > 0) drift.push(`${key} would grant ${added.join(", ")}`);
|
|
1004
|
+
}
|
|
1005
|
+
// A protection that disappears is a weakening even though the list shrank.
|
|
1006
|
+
for (const key of RESTRICTING_PERMISSIONS) {
|
|
1007
|
+
const kept = new Set(resolved[key] ?? []);
|
|
1008
|
+
const dropped = (locked[key] ?? []).filter((item) => !kept.has(item));
|
|
1009
|
+
if (dropped.length > 0) drift.push(`${key} would stop covering ${dropped.join(", ")}`);
|
|
1010
|
+
}
|
|
1011
|
+
return drift;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
export function classifyCapabilityLock(expected, actual) {
|
|
1015
|
+
const expectedDigest = sha256(stableJson(expected));
|
|
1016
|
+
const actualDigest = sha256(stableJson(actual));
|
|
1017
|
+
if (crypto.timingSafeEqual(Buffer.from(expectedDigest), Buffer.from(actualDigest))) {
|
|
1018
|
+
return { status: "current", reasons: [], expectedDigest, actualDigest };
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
const reasons = [...consentDrift(expected, actual), ...permissionDrift(expected, actual)];
|
|
1022
|
+
if (reasons.length > 0) return { status: "blocked", reasons, expectedDigest, actualDigest };
|
|
1023
|
+
|
|
1024
|
+
return {
|
|
1025
|
+
status: "repin",
|
|
1026
|
+
reasons: [`platform build moved to ${expected?.core?.packageVersion ?? "an unknown version"}`],
|
|
1027
|
+
expectedDigest,
|
|
1028
|
+
actualDigest
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
|
|
934
1032
|
export function verifyCapabilityLock(root, profilePath, lockDocument, options = {}) {
|
|
935
1033
|
const expected = resolveCapabilityProfile(root, profilePath, {
|
|
936
1034
|
packageSource: options.packageSource,
|
|
937
1035
|
extraRoots: options.extraRoots
|
|
938
1036
|
});
|
|
939
|
-
const
|
|
940
|
-
const actualText = stableJson(lockDocument);
|
|
1037
|
+
const classification = classifyCapabilityLock(expected, lockDocument);
|
|
941
1038
|
return {
|
|
942
|
-
ok:
|
|
943
|
-
|
|
944
|
-
|
|
1039
|
+
// `ok` stays the question callers were already asking: may this project run?
|
|
1040
|
+
// A re-pinnable lock may, and the caller is told so through `status`.
|
|
1041
|
+
ok: classification.status !== "blocked",
|
|
1042
|
+
status: classification.status,
|
|
1043
|
+
reasons: classification.reasons,
|
|
1044
|
+
expectedDigest: classification.expectedDigest,
|
|
1045
|
+
actualDigest: classification.actualDigest,
|
|
945
1046
|
expected
|
|
946
1047
|
};
|
|
947
1048
|
}
|