Files
姚章浩 693cd952cd feat(asset): 清理被截断的结尾图片引用,修复整单 502
仓库首次入库(此前仅存在于本地工作区与测试服构建产物中,未上传)。

改动(src/knowledge_adapter/asset_content_processor.py):
- 新增 _TRUNCATED_TRAILING_MARKDOWN_RESOURCE_IMAGE 规则,清除 chunk 末尾被截断的
  ![](resource://xxxx 残片(WeKnora 分块在图片引用中间截断时产生,旧逻辑无法匹配完整引用,
  残留 resource:// 触发 ContentProcessingError,导致整单 502)
- 回归测试 tests/test_asset_content_processor.py::
  test_truncated_trailing_markdown_resource_image_is_removed

验证证据:
- 测试服 120.76.217.51,镜像 knowledge-adapter-service:reviewed-test-aeab4b5fca2d
  (release aeab4b5fca2d8661):KB d015d05c-25c8-4d63-b2ab-e8590d3c2dfb 5 个查询全部
  http=200、records=5、残留 resource:// = 0;KB b9dacd62 无退化;容器日志无 error/exception
- 本地:pytest 141 项全通过、ruff 全通过
- 该文件与 258c31e0fe07fd08 源码的差异经逐文件 md5 比对,为唯一变更文件
2026-09-16 10:01:27 +08:00

130 lines
7.9 KiB
Markdown

# Slice 9 Verification and E2E Audit Report
- Project: Knowledge Adapter Service
- Repository: `/home/zheromiku/knowledge-adapter-service`
- Audit timestamp: `2026-08-24T18:44:35+08:00`
- Environment observed: local physical Inspur NF5568M4 host
- Scope: code/config validation and authorized read-only test-environment probes
- Production deployment: prohibited and not attempted
## Executive conclusion
The application implementation and source-delivery gates pass. The initial pre-report full suite completed with `133 passed in 1.06s`; after adding the audit artifact contract, the final full suite completed with `134 passed in 1.15s`. Ruff returned `All checks passed!`; the RAM policy parsed; the documentation citation ledger verified; and Docker Compose rendered successfully.
The real `Dify → Adapter → WeKnora → Adapter DB → OSS` E2E is **BLOCKED**, not failed and not passed. This host lacks the three dedicated Adapter Secret files, an authorized Docker daemon, a running Adapter candidate, a test Dify binding, and—critically—the Alibaba Cloud ECS RAM Role/IMDSv2 environment required by the production signer. No cloud result has been fabricated.
Production deployment remains **NOT RUN** by design.
## Requirement-to-evidence matrix
| Gate | Status | Evidence |
|---|---|---|
| Python runtime | PASS | `uv run python --version` → Python 3.12.11 |
| Full pytest before audit artifact | PASS | 133 tests collected; `133 passed in 1.06s` |
| Final full pytest | PASS | 134 tests collected; `134 passed in 1.15s` |
| Ruff | PASS | `uv run ruff check src tests` → `All checks passed!` |
| RAM policy JSON | PASS | `python -m json.tool ...` exited 0 |
| OSS permission contract | PASS (static) | Exact Action is `oss:GetObject`; resource is one configured bucket/tenant prefix |
| Security source citations | PASS | grounded-citations strict verify exited 0; four registered sources |
| Compose parse/render | PASS | `docker compose ... config --quiet` exited 0 |
| Compose service inventory | PASS | exactly `adapter`; image `knowledge-adapter-service:reviewed-test` |
| Existing WeKnora network integration | PASS (static) | Adapter joins configurable external `WEKNORA_NETWORK_NAME`; local baseline is `weknora071full-network`, App URL `http://app:8080` |
| Existing WeKnora /health | PASS (runtime/read-only) | `http://127.0.0.1:8080/health` returned HTTP 200 JSON |
| Dockerfile native build check | BLOCKED | Docker daemon permission denied at `/var/run/docker.sock`; no sudo or socket workaround used |
| Docker image build | BLOCKED | Same Docker daemon permission boundary |
| Container runtime/UID/mount health | BLOCKED | Adapter was not built or started; `127.0.0.1:18080` is closed |
| Nginx native syntax test | BLOCKED | `nginx binary unavailable` on this host; source-contract test passes only |
| Adapter DB migration rehearsal | BLOCKED | dedicated `asset_database_url` Secret/account/database are absent |
| WeKnora field-level grant rehearsal | BLOCKED | dedicated `weknora_readonly_database_url` Secret/account is absent |
| Test Dify external knowledge call | BLOCKED | no test Dify endpoint/binding/key was provided to this environment |
| Real cloud E2E | BLOCKED | no running Adapter candidate and no Alibaba ECS RAM Role/IMDSv2 context |
| Private OSS anonymous denial | BLOCKED | no authorized test-ECS signer path and no approved object fixture |
| OSS V4 signed-object fetch | BLOCKED | same prerequisite gap; Presigned URL was not generated or printed |
| 600-second expiry | BLOCKED | requires waiting against a real signed URL on test ECS |
| stable UUID re-signing | BLOCKED | requires active Adapter DB mapping and two real redirect requests |
| historical Dify image reopen | BLOCKED | requires a real Dify conversation and stable UUID fixture |
| Production deployment | NOT RUN | explicitly outside the approved scope |
## Commands actually run
```text
uv run pytest -o addopts='' tests
uv run ruff check src tests
python -m json.tool deploy/ram/knowledge-adapter-oss-read-policy.json
docker compose --env-file deploy/adapter.env.example \
-f deploy/docker-compose.adapter.yml config --quiet
docker compose --env-file deploy/adapter.env.example \
-f deploy/docker-compose.adapter.yml config --services
docker compose --env-file deploy/adapter.env.example \
-f deploy/docker-compose.adapter.yml config --images
docker buildx build --check --progress=plain .
python .../grounded-citations/scripts/sources.py verify docs/security.md --strict
```
The build-check command returned only the Docker daemon permission error. It did not build an image or change container state.
## Read-only prerequisite findings
### Listening endpoints
```text
127.0.0.1:8080 open existing WeKnora App
127.0.0.1:8088 open existing WeKnora UI
127.0.0.1:18080 closed Adapter candidate not running
127.0.0.1:80 closed
127.0.0.1:443 closed
```
### Dedicated Secret files
All required files are missing:
```text
/opt/knowledge-adapter/secrets/weknora_api_key
/opt/knowledge-adapter/secrets/asset_database_url
/opt/knowledge-adapter/secrets/weknora_readonly_database_url
```
No Secret content was read or printed.
### ECS role prerequisite
The observed host reports `sys_vendor=Inspur` and `product_name=NF5568M4`. It is not the target Alibaba ECS test instance. The signer intentionally supports only ECS RAM Role temporary credentials via IMDSv2 and has no long-lived AccessKey fallback, so a real OSS redirect cannot be accepted on this host.
## Security assertions retained
- No WeKnora source or schema was modified.
- No production system was contacted or deployed.
- No Docker permission bypass or sudo was used.
- No raw Dify/WeKnora key, database DSN, OSS AccessKey, STS token, object key, Authorization header, knowledge body, or Presigned URL was printed or committed.
- No migration or grant was applied.
- No OSS bucket ACL/policy was changed.
- No object was uploaded, copied, deleted, or made public.
- No caller-controlled bucket, object key, endpoint, expiry, or arbitrary URL path was introduced.
## Remaining test-ECS acceptance procedure
The following steps must execute on an authorized Alibaba ECS **test** instance after the prerequisites are provisioned:
1. Confirm the reviewed ECS RAM Role is attached and IMDSv2 temporary credentials resolve without long-lived AK/SK.
2. Confirm the OSS bucket remains Private and the role policy grants only the reviewed `oss:GetObject` prefix.
3. Create the dedicated Adapter DB and WeKnora field-level read-only accounts; place all three values in UID 10001, mode `0400` Secret files.
4. Run the up migration and field-level grant in disposable/test databases, then prove unrelated columns/tables and all writes are denied to the WeKnora role.
5. Build the reviewed image, run native `nginx -t` against the complete target configuration, and start only the Adapter candidate.
6. Verify runtime UID 10001, read-only root, Secret mounts, external WeKnora network, `/healthz`, and sanitized logs.
7. Configure a test Dify External Knowledge endpoint and execute one allowlisted query containing an approved image fixture.
8. Prove Dify receives only the stable UUID URL and no locator/object key/internal endpoint/signature.
9. Request the stable UUID, follow the 302 without displaying its Location, and verify the expected object content/hash.
10. Prove direct anonymous OSS access is denied.
11. Wait beyond the fixed 600-second expiry and prove the old temporary URL is denied.
12. Request the unchanged stable UUID again and prove stable UUID re-signing yields a working fresh temporary URL.
13. Reopen a historical Dify message containing the UUID link and verify the image still loads.
14. Export sanitized request-ID-correlated evidence and rerun the full suite/Ruff/config gates before review.
## Decision
- Code and static delivery package: **PASS**.
- Existing WeKnora liveness: **PASS**.
- Real cloud E2E: **BLOCKED** pending test-ECS prerequisites.
- Production readiness/deployment: **NOT APPROVED / NOT RUN**.