test: define safe and audit resource rename contract
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
# Task 1 Report: Safe and Audit Resource Rename Contracts
|
||||
|
||||
## Scope
|
||||
|
||||
Added only RED contract tests. No production source, database table, or data migration code was changed.
|
||||
|
||||
## Contract Coverage
|
||||
|
||||
- Backend resource catalogue: `safe_rule`, `safe_event`, `safe_inspection`, and `safe_event_disposal` under `safety`; `audit_operation_log`, `audit_export_log`, and `audit_approval` under `audit`.
|
||||
- Backend routes: `/safety/safe_*`, the safe-event disposal action, `/audit/audit_*`, and the audit-approval action.
|
||||
- Frontend resource definitions: required `safe_event` and `audit_approval` resource/path declarations.
|
||||
|
||||
## RED Evidence
|
||||
|
||||
### Backend
|
||||
|
||||
Command run from `backend/api`:
|
||||
|
||||
```powershell
|
||||
$env:GIN_MODE='release'; go test ./internal/logic/platform ./internal/routers -run 'Test.*(Safe|Audit)' -v
|
||||
```
|
||||
|
||||
Result: **failed as expected** (exit code 1).
|
||||
|
||||
- `TestSafeAndAuditResourceContracts` reports the missing `safety/safe_rule` contract; the current catalogue still defines `saf_rule` (and the other historical `saf_*`/`aud_*` names).
|
||||
- `TestPlatformDeviceSafetyCommerceAndDeliveryRoutesFollowTheirContracts` reports unregistered `/heqi/platform/v1/safety/safe_*` routes and the `safe_event` disposal route.
|
||||
- `TestPlatformFinanceContentAndAuditRoutesFollowTheirContracts` reports unregistered `/heqi/platform/v1/audit/audit_*` routes and `/audit/audit_approval/:identity/approve`.
|
||||
|
||||
### Frontend
|
||||
|
||||
Command run from `frontend/platform_admin`:
|
||||
|
||||
```powershell
|
||||
node --test scripts/audit-check.test.mjs
|
||||
```
|
||||
|
||||
Result: **failed as expected** (exit code 1; 6 passing, 1 failing).
|
||||
|
||||
- The new `资源定义使用 safe 和 audit 前缀` test fails because `src/api/resources.ts` currently defines `saf_event` at `/safety/saf_event`; it therefore does not match the required `safe_event` declaration. The required `audit_approval` declaration remains absent as well.
|
||||
|
||||
## Handoff
|
||||
|
||||
The red baseline is intentional. The next task should rename production resource contracts, backend routes, and frontend definitions without preserving the historical public names.
|
||||
@@ -25,12 +25,21 @@ import (
|
||||
|
||||
func TestExpectedResources(t *testing.T) {
|
||||
assertContract(t, ExpectedResources(), "gas", "gas_basic", Writable, "list")
|
||||
assertContract(t, ExpectedResources(), "safety", "saf_event", Writable, "list")
|
||||
assertContract(t, ExpectedResources(), "ec", "ec_order_item", Writable, "list")
|
||||
assertContract(t, ExpectedResources(), "wallet", "wallet_ledger", ReadOnly, "list")
|
||||
assertContract(t, ExpectedResources(), "delivery", "delivery_track_point", ReadOnly, "list")
|
||||
}
|
||||
|
||||
func TestSafeAndAuditResourceContracts(t *testing.T) {
|
||||
assertContract(t, ExpectedResources(), "safety", "safe_rule", Writable, "list")
|
||||
assertContract(t, ExpectedResources(), "safety", "safe_event", Writable, "list")
|
||||
assertContract(t, ExpectedResources(), "safety", "safe_inspection", Writable, "list")
|
||||
assertContract(t, ExpectedResources(), "safety", "safe_event_disposal", AppendOnly, "list")
|
||||
assertContract(t, ExpectedResources(), "audit", "audit_operation_log", ReadOnly, "list")
|
||||
assertContract(t, ExpectedResources(), "audit", "audit_export_log", ReadOnly, "list")
|
||||
assertContract(t, ExpectedResources(), "audit", "audit_approval", ReadOnly, "list")
|
||||
}
|
||||
|
||||
func TestResourceDefinitionAllowsOnlySupportedMethods(t *testing.T) {
|
||||
if (ResourceDefinition{Mode: ReadOnly}).Allows(http.MethodPost) {
|
||||
t.Fatal("readonly allows POST")
|
||||
|
||||
@@ -101,7 +101,7 @@ func TestPlatformDeviceSafetyCommerceAndDeliveryRoutesFollowTheirContracts(t *te
|
||||
|
||||
for _, resource := range []string{
|
||||
"/device/dev_smart_cylinder_valve", "/device/dev_device_binding",
|
||||
"/safety/saf_rule", "/safety/saf_event", "/safety/saf_inspection",
|
||||
"/safety/safe_rule", "/safety/safe_event", "/safety/safe_inspection",
|
||||
"/ec/ec_category", "/ec/ec_product", "/ec/ec_product_attribute", "/ec/ec_product_image", "/ec/ec_cart", "/ec/ec_order", "/ec/ec_order_item", "/ec/ec_review",
|
||||
"/delivery/delivery_task", "/delivery/delivery_track",
|
||||
} {
|
||||
@@ -126,7 +126,7 @@ func TestPlatformDeviceSafetyCommerceAndDeliveryRoutesFollowTheirContracts(t *te
|
||||
}
|
||||
}
|
||||
|
||||
disposal := "/heqi/platform/v1/safety/saf_event/:identity/disposals"
|
||||
disposal := "/heqi/platform/v1/safety/safe_event/:identity/disposals"
|
||||
assertRouteMethods(t, routes, disposal, http.MethodPost)
|
||||
if routes[disposal][http.MethodDelete] {
|
||||
t.Fatal("safety event disposals must be append-only")
|
||||
@@ -157,7 +157,7 @@ func TestPlatformFinanceContentAndAuditRoutesFollowTheirContracts(t *testing.T)
|
||||
for _, resource := range []string{
|
||||
"/wallet/wallet", "/wallet/wallet_ledger", "/wallet/wallet_recharge", "/wallet/wallet_withdrawal",
|
||||
"/report/report", "/report/report_item", "/report/report_metric_snapshot",
|
||||
"/audit/aud_operation_log", "/audit/aud_export_log", "/audit/aud_approval",
|
||||
"/audit/audit_operation_log", "/audit/audit_export_log", "/audit/audit_approval",
|
||||
} {
|
||||
path := "/heqi/platform/v1" + resource
|
||||
assertRouteMethods(t, routes, path, http.MethodGet)
|
||||
@@ -169,7 +169,7 @@ func TestPlatformFinanceContentAndAuditRoutesFollowTheirContracts(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
assertRouteMethods(t, routes, "/heqi/platform/v1/audit/aud_approval/:identity/approve", http.MethodPost)
|
||||
assertRouteMethods(t, routes, "/heqi/platform/v1/audit/audit_approval/:identity/approve", http.MethodPost)
|
||||
}
|
||||
|
||||
func assertRouteMethods(t *testing.T, routes map[string]map[string]bool, path string, methods ...string) {
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import test from 'node:test';
|
||||
import { auditPlatform, scanInternalIdLeaks } from './audit-check.mjs';
|
||||
|
||||
const resourcesSource = readFileSync('src/api/resources.ts', 'utf8');
|
||||
|
||||
test('资源定义使用 safe 和 audit 前缀', () => {
|
||||
assert.match(resourcesSource, /define\('safe_event', '\/safety\/safe_event'/);
|
||||
assert.match(resourcesSource, /define\('audit_approval', '\/audit\/audit_approval'/);
|
||||
});
|
||||
|
||||
test('只读页面将状态变更视为违规写操作', () => {
|
||||
const failures = auditPlatform({
|
||||
manifest: { resources: [], routes: [] },
|
||||
|
||||
Reference in New Issue
Block a user