Own safety/gates/parameters in metadata/ and Agent prose in selection/, drop the monolithic Manual file, and keep confirmation aligned with per-tool runtime_gate. Co-authored-by: Cursor <cursoragent@cursor.com>
92 lines
5.4 KiB
Go
92 lines
5.4 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
package app
|
|
|
|
import (
|
|
"sort"
|
|
"testing"
|
|
)
|
|
|
|
type finalSchemaSafetyWant struct {
|
|
canonical string
|
|
effect string
|
|
risk string
|
|
confirmation string
|
|
idempotency string
|
|
}
|
|
|
|
func TestReviewedMutationSafetyReachesFinalSchema(t *testing.T) {
|
|
wants := []finalSchemaSafetyWant{
|
|
{canonical: "aitable.form_field_hide", effect: "write", risk: "medium", confirmation: "not_required", idempotency: "idempotent"},
|
|
{canonical: "chat.dismiss_group", effect: "destructive", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "drive.recycle_restore", effect: "write", risk: "medium", confirmation: "not_required", idempotency: "unknown"},
|
|
{canonical: "minutes.create_speaker_summary", effect: "write", risk: "medium", confirmation: "not_required", idempotency: "unknown"},
|
|
{canonical: "sheet.clear_range", effect: "write", risk: "medium", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "sheet.batch_update", effect: "write", risk: "medium", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "sheet.range_batch_clear", effect: "write", risk: "medium", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "sheet.group_dimension", effect: "write", risk: "medium", confirmation: "not_required", idempotency: "unknown"},
|
|
{canonical: "sheet.sort_filter", effect: "write", risk: "medium", confirmation: "not_required", idempotency: "unknown"},
|
|
{canonical: "sheet.ungroup_dimension", effect: "write", risk: "medium", confirmation: "not_required", idempotency: "unknown"},
|
|
}
|
|
assertFinalSchemaSafety(t, wants)
|
|
}
|
|
|
|
func TestDevAppWriteGuardRequiresFinalSchemaConfirmation(t *testing.T) {
|
|
wants := []finalSchemaSafetyWant{
|
|
{canonical: "dev.add_dev_app_members", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.apply_dev_app_permissions", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.create_dev_app", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.create_dev_app_version", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.delete_dev_app", effect: "destructive", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.disable_dev_app", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.disable_dev_app_robot", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.enable_dev_app", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.enable_dev_app_robot", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.publish_dev_app_version", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.remove_dev_app_members", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.remove_dev_app_permissions", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.set_extension_robot_config", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.set_extension_webapp_config", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.submit_robot_create_task", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.subscribe_dev_app_events", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.unsubscribe_dev_app_events", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.update_dev_app", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
{canonical: "dev.update_dev_app_security_config", effect: "write", risk: "high", confirmation: "user_required", idempotency: "unknown"},
|
|
}
|
|
assertFinalSchemaSafety(t, wants)
|
|
}
|
|
|
|
func assertFinalSchemaSafety(t *testing.T, wants []finalSchemaSafetyWant) {
|
|
t.Helper()
|
|
canonicals := make([]string, 0, len(wants))
|
|
for _, want := range wants {
|
|
canonicals = append(canonicals, want.canonical)
|
|
}
|
|
sort.Strings(canonicals)
|
|
payload := schemaContractPayloadForBoundCanonicals(t, NewRootCommand(), canonicals...)
|
|
|
|
for _, want := range wants {
|
|
want := want
|
|
t.Run(want.canonical, func(t *testing.T) {
|
|
tool := payload.Tools[want.canonical]
|
|
values := map[string]string{
|
|
"effect": want.effect,
|
|
"risk": want.risk,
|
|
"confirmation": want.confirmation,
|
|
"idempotency": want.idempotency,
|
|
}
|
|
provenance := schemaContractMap(tool["field_provenance"])
|
|
for field, expected := range values {
|
|
if got := schemaContractString(tool[field]); got != expected {
|
|
t.Errorf("%s = %q, want %q", field, got, expected)
|
|
}
|
|
if got := schemaContractString(provenance[field]["precedence"]); got != "reviewed_explicit" {
|
|
t.Errorf("%s provenance precedence = %q, want reviewed_explicit", field, got)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|