Merge authoritative main into the task branch
Why: include the current integration baseline before verification. Evidence: fetched origin/main=5aae47ebca20ad1f3add3b080212cca7e1c6edf9. Impact: integrate upstream changes without rewriting task history. Refs: task-sync
This commit is contained in:
+155
-13
File diff suppressed because one or more lines are too long
@@ -0,0 +1,32 @@
|
||||
[
|
||||
{
|
||||
"original": "/tmp/project-member-rdm-final-gate-2973.json",
|
||||
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json",
|
||||
"sha256": "c66c14f86bfeb60578ce1d694b1070c770a1c951b9368c3d7406729fa7494b00",
|
||||
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
|
||||
},
|
||||
{
|
||||
"original": "/tmp/project-member-rdm-actual-merge-354.json",
|
||||
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json",
|
||||
"sha256": "bffb0c17ee3e2042aceea5263db1e71c22010e5119018b180bfc9287a49fc6b1",
|
||||
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
|
||||
},
|
||||
{
|
||||
"original": "/tmp/project-member-rdm-upstream-final-review.md",
|
||||
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md",
|
||||
"sha256": "919b78f85f0b6a5426494c4f47e4dda98a997422f10385c6e9481327751faca2",
|
||||
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
|
||||
},
|
||||
{
|
||||
"original": "/tmp/project-member-rdm-tag-final-review.md",
|
||||
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md",
|
||||
"sha256": "b67566a39c913652a5349a41c0b574fa8a9e7382a6b5963b4affdb73ecbe5cf9",
|
||||
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
|
||||
},
|
||||
{
|
||||
"original": "/tmp/project-member-rdm-synced-final-test.json",
|
||||
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json",
|
||||
"sha256": "ec5d2b2cd64ebf43bd3c9a811eb1e1be2821d9e3a6376b78babe84234683748a",
|
||||
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"actual_merge": "249d7980028f035124f6a74dd9cae132084b81c5",
|
||||
"tested_head": "7243a7044c9a4d96292efbb88acc219cac08d321",
|
||||
"tree": "a29f99852c0d49cf9138698c4bcdee356de36dcd",
|
||||
"pins": {
|
||||
"modules/backend": "5d5fc9891c0eb8994545ccb8b740535d9b99fb0e",
|
||||
"modules/frontend": "eb2d6d32f9323094d568bc9d80b4e5ed4f0af25b",
|
||||
"modules/documents": "047d362c72ec2c095ec14e1d2f2d152f94471faf",
|
||||
"modules/core": "5773e74086791731059730bd3726dc8c9cd1381f",
|
||||
"modules/ui": "2c4322ef56df64ad72f65907d25b048a74bb5ffc"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import subprocess,sys
|
||||
from pathlib import Path
|
||||
base=sys.argv[1]
|
||||
allowed_prefixes=('.task/artifacts/project-member-access-receipts/',)
|
||||
allowed={'.task/feature-project-member-access.md','.task/archive/feature-project-member-access.md'}
|
||||
files=subprocess.check_output(['git','diff','--name-only',base,'HEAD'],text=True).splitlines()
|
||||
assert files and all(p in allowed or p.startswith(allowed_prefixes) for p in files),files
|
||||
card=Path('.task/archive/feature-project-member-access.md')
|
||||
assert card.is_file() and not Path('.task/feature-project-member-access.md').exists()
|
||||
s=card.read_text()
|
||||
assert '状态:已完成' in s and 'https://git-home.u1680832.nyat.app:30319/weichen/' in s.splitlines()[2]
|
||||
assert '8788' in s
|
||||
subprocess.run(['git','diff','--check',base,'HEAD'],check=True)
|
||||
print('Scoped archive check PASS: only this task card and its original receipts changed; product and unrelated cards unchanged.')
|
||||
for p in files: print(p)
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,454 @@
|
||||
{
|
||||
"run": {
|
||||
"id": 2952,
|
||||
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/runs/2952",
|
||||
"previous_attempt_url": null,
|
||||
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/actions/runs/2952",
|
||||
"display_title": "Record merged-component final sync evidence",
|
||||
"path": "ci.yaml@refs/pull/526/head",
|
||||
"event": "pull_request",
|
||||
"run_attempt": 1,
|
||||
"run_number": 1520,
|
||||
"repository_id": 0,
|
||||
"head_sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
|
||||
"status": "completed",
|
||||
"actor": {
|
||||
"id": 1,
|
||||
"login": "weichen",
|
||||
"login_name": "",
|
||||
"source_id": 0,
|
||||
"full_name": "",
|
||||
"email": "1+weichen@noreply.git-panel.u1680832.nyat.app",
|
||||
"avatar_url": "https://git-home.u1680832.nyat.app:30319/avatars/51e6cd4a83883a2910632d26ebc6d665",
|
||||
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen",
|
||||
"language": "",
|
||||
"is_admin": false,
|
||||
"last_login": "0001-01-01T00:00:00Z",
|
||||
"created": "2026-09-06T14:39:07Z",
|
||||
"restricted": false,
|
||||
"active": false,
|
||||
"prohibit_login": false,
|
||||
"location": "",
|
||||
"website": "",
|
||||
"description": "",
|
||||
"visibility": "public",
|
||||
"followers_count": 0,
|
||||
"following_count": 0,
|
||||
"starred_repos_count": 0,
|
||||
"username": "weichen"
|
||||
},
|
||||
"trigger_actor": {
|
||||
"id": 1,
|
||||
"login": "weichen",
|
||||
"login_name": "",
|
||||
"source_id": 0,
|
||||
"full_name": "",
|
||||
"email": "1+weichen@noreply.git-panel.u1680832.nyat.app",
|
||||
"avatar_url": "https://git-home.u1680832.nyat.app:30319/avatars/51e6cd4a83883a2910632d26ebc6d665",
|
||||
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen",
|
||||
"language": "",
|
||||
"is_admin": false,
|
||||
"last_login": "0001-01-01T00:00:00Z",
|
||||
"created": "2026-09-06T14:39:07Z",
|
||||
"restricted": false,
|
||||
"active": false,
|
||||
"prohibit_login": false,
|
||||
"location": "",
|
||||
"website": "",
|
||||
"description": "",
|
||||
"visibility": "public",
|
||||
"followers_count": 0,
|
||||
"following_count": 0,
|
||||
"starred_repos_count": 0,
|
||||
"username": "weichen"
|
||||
},
|
||||
"repository": {
|
||||
"id": 29,
|
||||
"owner": {
|
||||
"id": 1,
|
||||
"login": "weichen",
|
||||
"login_name": "",
|
||||
"source_id": 0,
|
||||
"full_name": "",
|
||||
"email": "1+weichen@noreply.git-panel.u1680832.nyat.app",
|
||||
"avatar_url": "https://git-home.u1680832.nyat.app:30319/avatars/51e6cd4a83883a2910632d26ebc6d665",
|
||||
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen",
|
||||
"language": "",
|
||||
"is_admin": false,
|
||||
"last_login": "0001-01-01T00:00:00Z",
|
||||
"created": "2026-09-06T14:39:07Z",
|
||||
"restricted": false,
|
||||
"active": false,
|
||||
"prohibit_login": false,
|
||||
"location": "",
|
||||
"website": "",
|
||||
"description": "",
|
||||
"visibility": "public",
|
||||
"followers_count": 0,
|
||||
"following_count": 0,
|
||||
"starred_repos_count": 0,
|
||||
"username": "weichen"
|
||||
},
|
||||
"name": "Agent-System-Dev",
|
||||
"full_name": "weichen/Agent-System-Dev",
|
||||
"description": "开发集成仓:以 submodule 固定全部模块组合,承载跨仓构建、测试编排与原生(非容器)开发环境;发布物在 Agent-System-Releases。",
|
||||
"empty": false,
|
||||
"private": false,
|
||||
"fork": false,
|
||||
"template": false,
|
||||
"mirror": false,
|
||||
"size": 23204,
|
||||
"language": "Shell",
|
||||
"languages_url": "https://git-panel.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/languages",
|
||||
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev",
|
||||
"url": "https://git-panel.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev",
|
||||
"link": "",
|
||||
"ssh_url": "ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git",
|
||||
"clone_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev.git",
|
||||
"original_url": "",
|
||||
"website": "",
|
||||
"stars_count": 0,
|
||||
"forks_count": 0,
|
||||
"watchers_count": 1,
|
||||
"branch_count": 46,
|
||||
"open_issues_count": 1,
|
||||
"open_pr_counter": 8,
|
||||
"release_counter": 0,
|
||||
"default_branch": "main",
|
||||
"archived": false,
|
||||
"created_at": "2026-09-29T08:29:40Z",
|
||||
"updated_at": "2026-10-13T11:54:42Z",
|
||||
"archived_at": "1970-01-01T00:00:00Z",
|
||||
"permissions": {
|
||||
"admin": false,
|
||||
"push": false,
|
||||
"pull": false
|
||||
},
|
||||
"has_code": true,
|
||||
"has_issues": true,
|
||||
"internal_tracker": {
|
||||
"enable_time_tracker": true,
|
||||
"allow_only_contributors_to_track_time": true,
|
||||
"enable_issue_dependencies": true
|
||||
},
|
||||
"has_wiki": true,
|
||||
"has_pull_requests": true,
|
||||
"has_projects": true,
|
||||
"projects_mode": "all",
|
||||
"has_releases": true,
|
||||
"has_packages": true,
|
||||
"has_actions": true,
|
||||
"ignore_whitespace_conflicts": false,
|
||||
"allow_merge_commits": true,
|
||||
"allow_rebase": true,
|
||||
"allow_rebase_explicit": true,
|
||||
"allow_squash_merge": true,
|
||||
"allow_fast_forward_only_merge": true,
|
||||
"allow_merge_update": true,
|
||||
"allow_rebase_update": true,
|
||||
"allow_manual_merge": false,
|
||||
"autodetect_manual_merge": false,
|
||||
"default_delete_branch_after_merge": false,
|
||||
"default_merge_style": "merge",
|
||||
"default_update_style": "merge",
|
||||
"default_allow_maintainer_edit": true,
|
||||
"avatar_url": "",
|
||||
"internal": false,
|
||||
"mirror_interval": "",
|
||||
"object_format_name": "sha1",
|
||||
"mirror_updated": "0001-01-01T00:00:00Z",
|
||||
"mirror_last_sync_at": "0001-01-01T00:00:00Z",
|
||||
"topics": [],
|
||||
"licenses": []
|
||||
},
|
||||
"conclusion": "success",
|
||||
"pull_requests": [
|
||||
{
|
||||
"id": 1488,
|
||||
"number": 526,
|
||||
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/pulls/526",
|
||||
"head": {
|
||||
"ref": "feature/project-member-access",
|
||||
"sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
|
||||
"repo": {
|
||||
"id": 29,
|
||||
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev",
|
||||
"name": "Agent-System-Dev"
|
||||
}
|
||||
},
|
||||
"base": {
|
||||
"ref": "main",
|
||||
"sha": "d2c23f3a55a77711ded4328aa6215d9469c2b420",
|
||||
"repo": {
|
||||
"id": 29,
|
||||
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev",
|
||||
"name": "Agent-System-Dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"started_at": "2026-10-13T11:54:43Z",
|
||||
"completed_at": "2026-10-13T12:03:33Z"
|
||||
},
|
||||
"jobs": [
|
||||
{
|
||||
"id": 4419,
|
||||
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/jobs/4419",
|
||||
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/actions/runs/2952/jobs/4419",
|
||||
"run_id": 2952,
|
||||
"run_url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/runs/2952",
|
||||
"name": "test",
|
||||
"labels": [
|
||||
"ubuntu-latest"
|
||||
],
|
||||
"run_attempt": 1,
|
||||
"head_sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"runner_id": 3,
|
||||
"runner_name": "home-runner",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Checkout",
|
||||
"number": 0,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:54:44Z",
|
||||
"completed_at": "2026-10-13T11:54:53Z"
|
||||
},
|
||||
{
|
||||
"name": "Install Go 1.27.1",
|
||||
"number": 1,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:54:53Z",
|
||||
"completed_at": "2026-10-13T11:54:58Z"
|
||||
},
|
||||
{
|
||||
"name": "Install Node 22",
|
||||
"number": 2,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:54:58Z",
|
||||
"completed_at": "2026-10-13T11:55:01Z"
|
||||
},
|
||||
{
|
||||
"name": "Install house-style Python packages",
|
||||
"number": 3,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:55:01Z",
|
||||
"completed_at": "2026-10-13T11:55:05Z"
|
||||
},
|
||||
{
|
||||
"name": "make test (boundaries, pins, libs, core, backend, frontend, ui, agent-command)",
|
||||
"number": 4,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:55:05Z",
|
||||
"completed_at": "2026-10-13T11:59:43Z"
|
||||
},
|
||||
{
|
||||
"name": "Build the single binary",
|
||||
"number": 5,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:59:43Z",
|
||||
"completed_at": "2026-10-13T12:00:04Z"
|
||||
}
|
||||
],
|
||||
"created_at": "2026-10-13T11:54:42Z",
|
||||
"started_at": "2026-10-13T11:54:43Z",
|
||||
"completed_at": "2026-10-13T12:00:06Z"
|
||||
},
|
||||
{
|
||||
"id": 4420,
|
||||
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/jobs/4420",
|
||||
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/actions/runs/2952/jobs/4420",
|
||||
"run_id": 2952,
|
||||
"run_url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/runs/2952",
|
||||
"name": "test-pg",
|
||||
"labels": [
|
||||
"ubuntu-latest"
|
||||
],
|
||||
"run_attempt": 1,
|
||||
"head_sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"runner_id": 3,
|
||||
"runner_name": "home-runner",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Checkout",
|
||||
"number": 0,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:54:44Z",
|
||||
"completed_at": "2026-10-13T11:54:53Z"
|
||||
},
|
||||
{
|
||||
"name": "Install Go 1.27.1",
|
||||
"number": 1,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:54:53Z",
|
||||
"completed_at": "2026-10-13T11:54:57Z"
|
||||
},
|
||||
{
|
||||
"name": "Install house-style Python packages",
|
||||
"number": 2,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:54:57Z",
|
||||
"completed_at": "2026-10-13T11:55:02Z"
|
||||
},
|
||||
{
|
||||
"name": "Install PostgreSQL, pgvector and Redis",
|
||||
"number": 3,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:55:02Z",
|
||||
"completed_at": "2026-10-13T11:56:09Z"
|
||||
},
|
||||
{
|
||||
"name": "Start PostgreSQL and Redis",
|
||||
"number": 4,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:56:09Z",
|
||||
"completed_at": "2026-10-13T11:56:12Z"
|
||||
},
|
||||
{
|
||||
"name": "Backend tests against real PostgreSQL and Redis (required, no silent skip)",
|
||||
"number": 5,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:56:12Z",
|
||||
"completed_at": "2026-10-13T11:56:36Z"
|
||||
},
|
||||
{
|
||||
"name": "Two-process HTTP acceptance over shared PostgreSQL (U7, required)",
|
||||
"number": 6,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:56:36Z",
|
||||
"completed_at": "2026-10-13T11:57:02Z"
|
||||
},
|
||||
{
|
||||
"name": "RDM lifecycle pin is three fixed SHAs",
|
||||
"number": 7,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:57:02Z",
|
||||
"completed_at": "2026-10-13T11:57:02Z"
|
||||
},
|
||||
{
|
||||
"name": "Clone Agent-System-RDM with nested pins (reviewed allowlist addition)",
|
||||
"number": 8,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:57:02Z",
|
||||
"completed_at": "2026-10-13T11:58:24Z"
|
||||
},
|
||||
{
|
||||
"name": "Install Node 22",
|
||||
"number": 9,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:58:24Z",
|
||||
"completed_at": "2026-10-13T11:58:27Z"
|
||||
},
|
||||
{
|
||||
"name": "Build the real agent-system binary",
|
||||
"number": 10,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:58:27Z",
|
||||
"completed_at": "2026-10-13T11:58:47Z"
|
||||
},
|
||||
{
|
||||
"name": "Real-combination lifecycle gate (make test-lifecycle, required)",
|
||||
"number": 11,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:58:47Z",
|
||||
"completed_at": "2026-10-13T12:03:31Z"
|
||||
}
|
||||
],
|
||||
"created_at": "2026-10-13T11:54:42Z",
|
||||
"started_at": "2026-10-13T11:54:44Z",
|
||||
"completed_at": "2026-10-13T12:03:33Z"
|
||||
},
|
||||
{
|
||||
"id": 4421,
|
||||
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/jobs/4421",
|
||||
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/actions/runs/2952/jobs/4421",
|
||||
"run_id": 2952,
|
||||
"run_url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/runs/2952",
|
||||
"name": "svc-realcombo",
|
||||
"labels": [
|
||||
"ubuntu-latest"
|
||||
],
|
||||
"run_attempt": 1,
|
||||
"head_sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"runner_id": 3,
|
||||
"runner_name": "home-runner",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Checkout",
|
||||
"number": 0,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:54:44Z",
|
||||
"completed_at": "2026-10-13T11:54:53Z"
|
||||
},
|
||||
{
|
||||
"name": "Install Go 1.27.1",
|
||||
"number": 1,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:54:53Z",
|
||||
"completed_at": "2026-10-13T11:54:57Z"
|
||||
},
|
||||
{
|
||||
"name": "Install Node 22",
|
||||
"number": 2,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:54:57Z",
|
||||
"completed_at": "2026-10-13T11:55:01Z"
|
||||
},
|
||||
{
|
||||
"name": "Build the real agent-system binary",
|
||||
"number": 3,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:55:01Z",
|
||||
"completed_at": "2026-10-13T11:56:42Z"
|
||||
},
|
||||
{
|
||||
"name": "Clone Agent-System-RDM with nested pins (reviewed allowlist addition)",
|
||||
"number": 4,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:56:42Z",
|
||||
"completed_at": "2026-10-13T11:57:05Z"
|
||||
},
|
||||
{
|
||||
"name": "Run real-combination lifecycle gates (SQLite, U3, required)",
|
||||
"number": 5,
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2026-10-13T11:57:05Z",
|
||||
"completed_at": "2026-10-13T11:57:33Z"
|
||||
}
|
||||
],
|
||||
"created_at": "2026-10-13T11:54:42Z",
|
||||
"started_at": "2026-10-13T11:54:44Z",
|
||||
"completed_at": "2026-10-13T11:57:34Z"
|
||||
}
|
||||
],
|
||||
"verified_head": "7243a7044c9a4d96292efbb88acc219cac08d321"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"component": "backend",
|
||||
"merged": "5d5fc9891c0eb8994545ccb8b740535d9b99fb0e",
|
||||
"tree": "f2c80faac929a26ca51036dfd2aa54b6dec8553f",
|
||||
"tested": "d26f3cf2e864a76ad0b868fd968da3257cc7bb44"
|
||||
},
|
||||
{
|
||||
"component": "frontend",
|
||||
"merged": "eb2d6d32f9323094d568bc9d80b4e5ed4f0af25b",
|
||||
"tree": "95498c511e440dc3711c626c0f8cd04fb81b84af",
|
||||
"tested": "40c2afe05449b30e4ed92991487f4eac57221366"
|
||||
},
|
||||
{
|
||||
"component": "documents",
|
||||
"merged": "047d362c72ec2c095ec14e1d2f2d152f94471faf",
|
||||
"tree": "eb46876d3a10f4c0b37eb134fc22f40c2b3b1216",
|
||||
"tested": "6c096b9360094bec9f5d8c9a6db0c701da463fca"
|
||||
}
|
||||
]
|
||||
+34
File diff suppressed because one or more lines are too long
+34
File diff suppressed because one or more lines are too long
+34
File diff suppressed because one or more lines are too long
@@ -0,0 +1,18 @@
|
||||
# RDM v0.4.0 tag 消费独立复审
|
||||
|
||||
结论:PASS;本增量无 P1/P2 findings。审阅者 `/root/backend_review` 未参与产品实现,仅执行只读审阅、独立临时测试和隔离产品 smoke。
|
||||
|
||||
审阅范围:RDM `589f030a5f5b7b12fb9dfd7014a93fb98ff6a9f9` → `b03f27354b309d5d2d44bee0ab42718f37cea241`。四项 pin 与远端已发布 `v0.4.0` annotated tag 的 peeled commit 及本地 tag 一致:Backend `5d5fc9891c0eb8994545ccb8b740535d9b99fb0e`,Core `5773e74086791731059730bd3726dc8c9cd1381f`,Frontend `eb2d6d32f9323094d568bc9d80b4e5ed4f0af25b`,UI `2c4322ef56df64ad72f65907d25b048a74bb5ffc`。Core 直 pin 与 Backend 内嵌 Core 一致;Backend/Frontend 的完整源码树与此前验收对象一致。
|
||||
|
||||
独立重放使用仓内默认 `go.mod`、空 `GOFLAGS/GOWORK`,实际模块路径指向 `pins/`。项目、注册、canonical ID、私域、发布/epoch、职责与审计正文边界测试均通过。正式 `bin/agent-system-rdm-product` 在隔离 `/tmp` 数据和空闲端口启动:验证真实 `/proc` executable、React 根页及 JS asset、匿名 commands=401、认证后的项目/私域/发布命令注册;自有进程已停止,诊断数据保留,未触及 8788。
|
||||
|
||||
实际正式构建对象为 `0bb8bcc7f727954fc36f32978bf427379fcb435e`;到审阅 HEAD `b03f273...` 的 `git diff -- ':!.task'` 为空。Manifest 的构建对象及作者正式 make test 收据与该事实一致;不要求 manifest 冒称新的证据提交。已核实际 binary SHA256 `2ad5559aa8bce7b67dde0d3f1a41707f0808e1f2f447b6db0a2167995866a2e5`、dist 摘要 `3f1646dd90abaf03`、实际 served JS SHA256 `e7d21720387057e5592e386a9b1e292383956b30d4fb74b2835350fd4e9db4e4` 与现有 manifest/产物匹配。
|
||||
|
||||
原始现代工具收据(均保持 SELF;独立执行身份单独用于 REPLAY attestation):
|
||||
|
||||
- `/tmp/project-member-rdm-tag-independent-tests.json` — PASS,默认 go.mod 与聚焦测试。
|
||||
- `/tmp/project-member-rdm-tag-independent-smoke.json` — PASS,真实正式产品入口。
|
||||
- `/tmp/project-member-rdm-tag-independent-pins-product.json` — 原始 FAIL 保留;四 tag 核验已通过,失败原因是审阅脚本误断言 manifest 构建 SHA 必须等于证据 HEAD。
|
||||
- `/tmp/project-member-rdm-tag-independent-pins-product-v2.json` — PASS,按真实构建对象核验等价性及实际产物摘要。
|
||||
|
||||
RDM 自身旧版 `scripts/evidence.sh` 会写任务卡,本轮改用 Dev 的现代 wrapper 在 RDM cwd 的 RECEIPT 模式,未改产品、任务卡或索引。Root 的授权任务证据写入不改变上述固定产品对象。最终同步后的当前 HEAD CI、平台准入及 FF 合入由 root 另行核验;本报告不沿用旧 CI 作为新门禁,未执行部署。
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# RDM 上游同步增量独立复审
|
||||
|
||||
结论:PASS;本增量无 P1/P2 findings。审阅者 `/root/backend_review` 未参与实现,未修改源码、任务卡或索引,未操作 8788。
|
||||
|
||||
对象:`b03f27354b309d5d2d44bee0ab42718f37cea241` → `a4edf708336398552af6cf6f65f88807473d460c`。独立执行时 HEAD 已为证据提交 `c058bfcf651c42b2dfc9c93ec7cb1f1036d3fd95`;现代收据内先执行 `git diff --exit-code a4edf708 HEAD -- . ':!.task'`,确认为同一产品、治理脚本及 pins 对象。
|
||||
|
||||
账号 query/name 转发保留 canonical 项目注册与命令包装;目录读取先检查 member.manage,姓名仅随受管目录 DTO 返回,未增加联系方式。默认 go.mod、空 GOFLAGS 的账号目录、项目注册/canonical ID、成员权限/override/archive 相关测试通过。post-merge 和 task-finish 仅提示显式 task-close,4 个真实临时 Git 仓库治理用例通过;未自动扫描、归档、提交或推送其他任务卡。四 pins 与 go.mod 未变化。
|
||||
|
||||
原始现代工具收据(均保持 SELF;独立执行身份另作 attestation):
|
||||
|
||||
- `/tmp/project-member-rdm-upstream-independent-tests-v2.json` — PASS,默认模块账号/项目/权限重放。
|
||||
- `/tmp/project-member-rdm-upstream-independent-governance-v2.json` — PASS,make test-governance,4 用例。
|
||||
- `/tmp/project-member-rdm-upstream-independent-tests.json` — 首轮 HEAD guard FAIL,测试 NOT_RUN;保留。
|
||||
- `/tmp/project-member-rdm-upstream-independent-governance.json` — 首轮 HEAD guard FAIL,治理测试 NOT_RUN;保留。
|
||||
|
||||
已在独立重放后核验作者完整测试收据。此前 tag/正式产品/组合 Review 在未受影响范围保留;当前待合入 HEAD 的 CI、平台准入及实际合入由 root 单独核验,不以旧 CI 放行新 HEAD。
|
||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
# P8 第八节十场景验收(提案 rdm-settings-members-duties-perms-increment §8)。
|
||||
# 走真实 dev 服务 HTTP(--auth 会话),多账号多角色;输出逐场景 PASS/FAIL。
|
||||
# 用法:BASE=http://127.0.0.1:8788 ADMIN_USER=weichen ADMIN_PASS=<密码> ./acceptance_scenarios.sh
|
||||
# 走真实服务 HTTP(--auth 会话),多账号多角色;输出逐场景 PASS/FAIL。
|
||||
# v0.4.0 版:RDM 命令面用 rdm.project.create 的 RID(不再直用基座项目);
|
||||
# 场景 2 姓名过滤全量断言(基座 v0.4.0+ AccountSearcher);setRole→set-role(#350)。
|
||||
# 前置:ADMIN 账号须为基座管理员(改密门已过)且已登记 RDM 域管理员
|
||||
# (组合二进制 -bootstrap-admin <owner>,仅空台账生效)。
|
||||
# 用法:BASE=http://127.0.0.1:8799 ADMIN_USER=rootadmin ADMIN_PASS=<密码> ./acceptance_scenarios.sh
|
||||
set -u
|
||||
BASE="${BASE:-http://127.0.0.1:8788}"
|
||||
ADMIN_USER="${ADMIN_USER:?需要管理员账号}"
|
||||
@@ -33,19 +37,27 @@ JA="$T/admin"; login "$ADMIN_USER" "$ADMIN_PASS" "$JA"
|
||||
|
||||
say "== 准备:账号与两项目 =="
|
||||
TS=$(date +%s)
|
||||
# 建号:非管理员负责人 owner2 / 普通成员 mem1 / 三权三人 w1 a1 r1(密码同式)
|
||||
# 建号:非管理员负责人 owner2 / 普通成员 mem1 / 三权三人 w1 a1 r1(密码同式;name=角色-<u>)
|
||||
for u in owner2 mem1 w1 a1 r1; do
|
||||
resp=$(api "$JA" POST /api/admin/users "{\"owner\":\"$u\",\"name\":\"角色-$u\",\"password\":\"Pass-$TS-x8z\",\"isAdmin\":false}")
|
||||
[ "$(echo "$resp" | code)" = "200" ] || say " ($u 已存在或其他:$(echo "$resp" | code))"
|
||||
done
|
||||
# 各自完成改密门(登录→改密)
|
||||
# 各自完成改密门(登录→改密);基座 #195 起改密撤销旧会话 → 用新密码重登刷新 jar
|
||||
for u in owner2 mem1 w1 a1 r1; do
|
||||
J="$T/$u"; login "$u" "Pass-$TS-x8z" "$J"
|
||||
api "$J" POST /api/auth/password "{\"current\":\"Pass-$TS-x8z\",\"next\":\"Pass2-$TS\"}" >/dev/null
|
||||
login "$u" "Pass2-$TS" "$J"
|
||||
done
|
||||
JPASS="Pass2-$TS"
|
||||
|
||||
# 场景 10 前置数据 + 项目创建走 owner2(非管理员)
|
||||
RDM() { # jar cmd json
|
||||
api "$1" POST "/api/commands/$2" "{\"params\":$3}" | body
|
||||
}
|
||||
PAYLOAD() { # stdin json → payload 子对象(命令应答信封 {payload,receipt})
|
||||
python3 -c 'import json,sys; print(json.dumps(json.load(sys.stdin)["payload"], ensure_ascii=False))'
|
||||
}
|
||||
|
||||
# 基座项目(场景 1/10 用):owner2(非管理员)创建
|
||||
JO="$T/owner2"
|
||||
P1=$(api "$JO" POST /api/projects "{\"name\":\"验收甲-$TS\"}")
|
||||
PID1=$(echo "$P1" | body | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' 2>/dev/null)
|
||||
@@ -53,9 +65,15 @@ P2=$(api "$JO" POST /api/projects "{\"name\":\"验收乙-$TS\"}")
|
||||
PID2=$(echo "$P2" | body | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' 2>/dev/null)
|
||||
[ -n "${PID1:-}" ] && [ -n "${PID2:-}" ] && ok "准备:两项目创建($PID1 / $PID2)" || { bad "准备:项目创建" "$P1"; exit 1; }
|
||||
|
||||
RDM() { # jar cmd json
|
||||
api "$1" POST "/api/commands/$2" "{\"params\":$3}" | body
|
||||
}
|
||||
# RDM 项目(场景 2-8 用):域管理员建项(创建者自动为 owner)+ 绑定基座项目;
|
||||
# owner2 入项为 owner 后域管理员自移出——owner2 成为唯一 owner(场景 3b 前提)
|
||||
RID=$(RDM "$JA" rdm.project.create "{\"name\":\"验收RDM甲-$TS\"}" | python3 -c 'import json,sys; print(json.load(sys.stdin)["payload"]["projectId"])' 2>/dev/null)
|
||||
[ -n "${RID:-}" ] && ok "准备:RDM 项目创建($RID)" || { bad "准备:RDM 项目创建" ""; exit 1; }
|
||||
RDM "$JA" rdm.project.bind "{\"hostProjectId\":\"$PID1\",\"projectId\":\"$RID\"}" >/dev/null
|
||||
out=$(RDM "$JA" rdm.project.member.add "{\"projectId\":\"$RID\",\"member\":\"owner2\",\"role\":\"owner\"}")
|
||||
echo "$out" | grep -q '"owner"' || { bad "准备:owner2 入项" "$out"; exit 1; }
|
||||
out=$(RDM "$JA" rdm.project.member.remove "{\"projectId\":\"$RID\",\"member\":\"$ADMIN_USER\"}")
|
||||
echo "$out" | grep -q '"removed":true' && ok "准备:owner2 为 RDM 项目唯一 owner(管理员自移出)" || { bad "准备:管理员自移出" "$out"; exit 1; }
|
||||
|
||||
say "== 场景 1:受管项写入拒绝(user/project 层,含手造请求)=="
|
||||
r=$(api "$JO" PUT /api/settings/user '{"models":{"chat":{"model":"m-hack"}}}' | code)
|
||||
@@ -66,51 +84,68 @@ r=$(api "$JO" PUT "/api/settings/project/$PID1" '{"models":{"chat":{"apiKey":"sk
|
||||
r=$(api "$JO" PUT /api/settings/system '{"models":{"chat":{"model":"x"}}}' | code)
|
||||
[ "$r" = "403" ] && ok "1c 非管理员写系统面 403" || bad "1c" "$r"
|
||||
|
||||
say "== 场景 2:目录查找成员(账号/分页;姓名过滤待发版 tag 后全量)=="
|
||||
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$PID1\",\"limit\":5}")
|
||||
n=$(echo "$out" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(len(d.get("accounts",[])))' 2>/dev/null)
|
||||
say "== 场景 2:目录查找成员(账号/分页 + 姓名过滤 v0.4.0 全量)=="
|
||||
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$RID\",\"limit\":5}")
|
||||
n=$(echo "$out" | python3 -c 'import json,sys; d=json.load(sys.stdin)["payload"]; print(len(d.get("accounts",[])))' 2>/dev/null)
|
||||
[ "${n:-0}" -gt 0 ] && ok "2a 目录分页浏览($n 条)" || bad "2a" "$out"
|
||||
# 2b 姓名子串「角色-w」→ 仅 w1(角色-w1),姓名随行、检索无游标
|
||||
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$RID\",\"query\":\"角色-w\",\"limit\":20}")
|
||||
r=$(echo "$out" | python3 -c 'import json,sys
|
||||
d=json.load(sys.stdin)["payload"]; a=d.get("accounts",[])
|
||||
print("ok" if len(a)==1 and a[0]["owner"]=="w1" and a[0].get("name")=="角色-w1" and d.get("next","")=="" else json.dumps(d,ensure_ascii=False))' 2>/dev/null)
|
||||
[ "$r" = "ok" ] && ok "2b 姓名过滤「角色-w」仅 w1 且姓名随行无游标" || bad "2b" "$r"
|
||||
# 2c 账号子串大小写不敏感「MEM」→ 仅 mem1(角色-mem1)
|
||||
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$RID\",\"query\":\"MEM\",\"limit\":20}")
|
||||
r=$(echo "$out" | python3 -c 'import json,sys
|
||||
d=json.load(sys.stdin)["payload"]; a=d.get("accounts",[])
|
||||
print("ok" if len(a)==1 and a[0]["owner"]=="mem1" and a[0].get("name")=="角色-mem1" else json.dumps(d,ensure_ascii=False))' 2>/dev/null)
|
||||
[ "$r" = "ok" ] && ok "2c 账号过滤「MEM」(不区分大小写)仅 mem1" || bad "2c" "$r"
|
||||
# 2d 多命中(角色- 前缀 5 人)+ limit 截断
|
||||
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$RID\",\"query\":\"角色\",\"limit\":3}")
|
||||
r=$(echo "$out" | python3 -c 'import json,sys
|
||||
d=json.load(sys.stdin)["payload"]; a=d.get("accounts",[])
|
||||
print("ok" if len(a)==3 and all(str(e.get("name","")).startswith("角色-") for e in a) else json.dumps(d,ensure_ascii=False))' 2>/dev/null)
|
||||
[ "$r" = "ok" ] && ok "2d 多命中姓名检索按 limit 截断(3/5)" || bad "2d" "$r"
|
||||
|
||||
say "== 场景 3:重复添加与最后负责人保护 =="
|
||||
RDM "$JO" rdm.project.member.add "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"member\"}" >/dev/null
|
||||
out=$(RDM "$JO" rdm.project.member.add "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"owner\"}")
|
||||
RDM "$JO" rdm.project.member.add "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"member\"}" >/dev/null
|
||||
out=$(RDM "$JO" rdm.project.member.add "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"owner\"}")
|
||||
echo "$out" | grep -q "已是成员" && ok "3a 重复添加拒绝且不隐式变更" || bad "3a" "$out"
|
||||
out=$(RDM "$JO" rdm.project.member.setRole "{\"projectId\":\"$PID1\",\"member\":\"owner2\",\"role\":\"member\"}")
|
||||
out=$(RDM "$JO" rdm.project.member.set-role "{\"projectId\":\"$RID\",\"member\":\"owner2\",\"role\":\"member\"}")
|
||||
echo "$out" | grep -q "最后一位负责人" && ok "3b 降级唯一负责人被拒" || bad "3b" "$out"
|
||||
out=$(RDM "$JO" rdm.project.member.setRole "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"owner\"}")
|
||||
out=$(RDM "$JO" rdm.project.member.set-role "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"owner\"}")
|
||||
echo "$out" | grep -q '"role":"owner"' && ok "3c 显式升级成功" || bad "3c" "$out"
|
||||
RDM "$JO" rdm.project.member.setRole "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"member\"}" >/dev/null
|
||||
RDM "$JO" rdm.project.member.set-role "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"member\"}" >/dev/null
|
||||
# 成员补充:三权三人入项目
|
||||
for u in w1 a1 r1; do RDM "$JO" rdm.project.member.add "{\"projectId\":\"$PID1\",\"member\":\"$u\"}" >/dev/null; done
|
||||
for u in w1 a1 r1; do RDM "$JO" rdm.project.member.add "{\"projectId\":\"$RID\",\"member\":\"$u\"}" >/dev/null; done
|
||||
|
||||
say "== 场景 4:文档目录与职责分配对象校验 =="
|
||||
# 建文档(经 RDM 世界初始化:用 rdm.init 或模板?最小:rdm.duty.catalog 应答;docId 误提交由场景 5 的 assign 覆盖
|
||||
cat_out=$(RDM "$JO" rdm.duty.catalog "{\"projectId\":\"$PID1\"}")
|
||||
echo "$cat_out" | python3 -c 'import json,sys; d=json.load(sys.stdin); assert "docs" in d' 2>/dev/null && ok "4a duty.catalog 目录可读" || bad "4a" "$cat_out"
|
||||
cat_out=$(RDM "$JO" rdm.duty.catalog "{\"projectId\":\"$RID\"}")
|
||||
echo "$cat_out" | python3 -c 'import json,sys; assert "docs" in json.load(sys.stdin)["payload"]' 2>/dev/null && ok "4a duty.catalog 目录可读" || bad "4a" "$cat_out"
|
||||
# 章节误提交:构造不存在的 docId → assign 拒绝
|
||||
out=$(RDM "$JO" rdm.review.assign.doc "{\"projectId\":\"$PID1\",\"docId\":\"section-not-doc\",\"author\":\"w1\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}")
|
||||
out=$(RDM "$JO" rdm.review.assign.doc "{\"projectId\":\"$RID\",\"docId\":\"section-not-doc\",\"author\":\"w1\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}")
|
||||
echo "$out" | grep -qE "不存在|失败|错误" && ok "4b 不存在对象整笔拒绝" || bad "4b" "$out"
|
||||
|
||||
say "== 场景 5:非成员职责目标被拒;移出成员保存被拒 =="
|
||||
out=$(RDM "$JO" rdm.review.assign.doc "{\"projectId\":\"$PID1\",\"docId\":\"any\",\"author\":\"zombie-$TS\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}")
|
||||
out=$(RDM "$JO" rdm.review.assign.doc "{\"projectId\":\"$RID\",\"docId\":\"any\",\"author\":\"zombie-$TS\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}")
|
||||
echo "$out" | grep -q "成员" && ok "5a 非成员职责目标被拒" || bad "5a" "$out"
|
||||
# mem1 移出后 setRole 保存拒绝
|
||||
RDM "$JO" rdm.project.member.remove "{\"projectId\":\"$PID1\",\"member\":\"mem1\"}" >/dev/null
|
||||
out=$(RDM "$JO" rdm.project.member.setRole "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"owner\"}")
|
||||
# mem1 移出后 set-role 保存拒绝
|
||||
RDM "$JO" rdm.project.member.remove "{\"projectId\":\"$RID\",\"member\":\"mem1\"}" >/dev/null
|
||||
out=$(RDM "$JO" rdm.project.member.set-role "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"owner\"}")
|
||||
echo "$out" | grep -q "不是" && ok "5b 移出成员的成员面操作被拒" || bad "5b" "$out"
|
||||
|
||||
say "== 场景 6:批量整批拒绝(预检列原因)=="
|
||||
out=$(RDM "$JO" rdm.review.assign.doc.batch "{\"projectId\":\"$PID1\",\"docs\":[{\"docId\":\"x1\",\"author\":\"w1\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"},{\"docId\":\"x2\",\"author\":\"zombie-$TS\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}]}")
|
||||
out=$(RDM "$JO" rdm.review.assign.doc.batch "{\"projectId\":\"$RID\",\"docs\":[{\"docId\":\"x1\",\"author\":\"w1\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"},{\"docId\":\"x2\",\"author\":\"zombie-$TS\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}]}")
|
||||
echo "$out" | grep -q "整批拒绝" && ok "6 批量含非成员整批拒绝并列原因" || bad "6" "$out"
|
||||
|
||||
say "== 场景 7:单成员解释与矩阵同源 =="
|
||||
chk=$(RDM "$JO" rdm.perm.check "{\"projectId\":\"$PID1\",\"member\":\"owner2\"}")
|
||||
mtx=$(RDM "$JO" rdm.perm.matrix "{\"projectId\":\"$PID1\"}")
|
||||
chk=$(RDM "$JO" rdm.perm.check "{\"projectId\":\"$RID\",\"member\":\"owner2\"}")
|
||||
mtx=$(RDM "$JO" rdm.perm.matrix "{\"projectId\":\"$RID\"}")
|
||||
same=$(python3 - "$chk" "$mtx" <<'PY'
|
||||
import json,sys
|
||||
c=json.loads(sys.argv[1]); m=json.loads(sys.argv[2])
|
||||
c=json.loads(sys.argv[1])["payload"]; m=json.loads(sys.argv[2])["payload"]
|
||||
row=[r for r in m.get("rows",[]) if r["member"]==c["member"]]
|
||||
if not row: print("no-row"); sys.exit(1)
|
||||
if not row: print("no-row"); sys.exit(0)
|
||||
ca={a["action"]:(a["allowed"],a.get("label"),a.get("scope")) for a in c["actions"]}
|
||||
ra={a["action"]:(a["allowed"],a.get("label"),a.get("scope")) for a in row[0]["actions"]}
|
||||
print("same" if ca==ra else "diff")
|
||||
@@ -119,15 +154,15 @@ PY
|
||||
[ "$same" = "same" ] && ok "7 单成员详情与矩阵单元格一致" || bad "7" "$same"
|
||||
# 普通成员自省:a1 查自己
|
||||
ja="$T/a1"
|
||||
out=$(RDM "$ja" rdm.perm.check "{\"projectId\":\"$PID1\",\"member\":\"a1\"}")
|
||||
out=$(RDM "$ja" rdm.perm.check "{\"projectId\":\"$RID\",\"member\":\"a1\"}")
|
||||
echo "$out" | grep -q '"actions"' && ok "7b 普通成员自省可用" || bad "7b" "$out"
|
||||
|
||||
say "== 场景 8:系统动作不可项目覆盖 =="
|
||||
out=$(RDM "$JO" rdm.perm.set "{\"projectId\":\"$PID1\",\"member\":\"a1\",\"action\":\"project.create\",\"allow\":true}")
|
||||
out=$(RDM "$JO" rdm.perm.set "{\"projectId\":\"$RID\",\"member\":\"a1\",\"action\":\"project.create\",\"allow\":true}")
|
||||
echo "$out" | grep -q "系统范围" && ok "8a project.create 覆盖被服务端拒绝" || bad "8a" "$out"
|
||||
out=$(RDM "$JO" rdm.perm.set "{\"projectId\":\"$PID1\",\"member\":\"a1\",\"action\":\"doc.write\",\"allow\":true}")
|
||||
echo "$out" | grep -q '"ok"' || echo "$out" | grep -q 'ok' && ok "8b 项目范围动作覆盖可用" || bad "8b" "$out"
|
||||
out=$(RDM "$JO" rdm.perm.unset "{\"projectId\":\"$PID1\",\"member\":\"a1\",\"action\":\"doc.write\"}")
|
||||
out=$(RDM "$JO" rdm.perm.set "{\"projectId\":\"$RID\",\"member\":\"a1\",\"action\":\"doc.write\",\"allow\":true}")
|
||||
echo "$out" | grep -q '"allow":true' && ok "8b 项目范围动作覆盖可用" || bad "8b" "$out"
|
||||
out=$(RDM "$JO" rdm.perm.unset "{\"projectId\":\"$RID\",\"member\":\"a1\",\"action\":\"doc.write\"}")
|
||||
echo "$out" | grep -q '"restored":true' && ok "8c 恢复默认(实际撤销)" || bad "8c" "$out"
|
||||
|
||||
say "== 场景 9:迟到响应/断网(UI 行为)=="
|
||||
|
||||
Reference in New Issue
Block a user