Screenshot guardrails: name every screenshot not COMPLETE on 409 ASSET_IN_POST_PROCESSING (submit, validate; stuck after 5 min in UPLOAD_COMPLETE), apple screenshots --repair-stuck replaces only those in place, part uploads without Expect: 100-continue (failed part deletes the reservation, one retry, never committed), storebound api --confirm <operationId> for agents' plain writes (never owner-only)
This commit is contained in:
parent
164182012f
commit
00756e6908
19 changed files with 475 additions and 45 deletions
|
|
@ -5,7 +5,7 @@ import { appleRows, generate, playRows, scanSource, templateRegex, wrappedOps }
|
|||
import { APPLE_OPS } from '../cli/api/apple.gen';
|
||||
import { PLAY_APIS, PLAY_OPS } from '../cli/api/play.gen';
|
||||
import { allOps, appleApi, backoffMs, buildRequest, getOp, mergePages, nextRequest, type Op, playApi, resolveOp, send, sendAll } from '../cli/api/client';
|
||||
import { decide, gateOf, type GateInput, OWNER_ONLY, ownerReason } from '../cli/api/gate';
|
||||
import { decide, gateOf, type GateInput, OWNER_NO_CONFIRM, OWNER_ONLY, ownerReason } from '../cli/api/gate';
|
||||
import { coverage, describeRequest, parseParams, rows, search } from '../cli/api';
|
||||
import { parseArgs } from '../cli/lib/args';
|
||||
import { TOOLS, toArgv, validateInput } from '../cli/mcp-tools';
|
||||
|
|
@ -180,6 +180,20 @@ describe('write gating', () => {
|
|||
expect(decide({ ...base, getOnly: true, method: 'POST' }).action).toBe('refuse');
|
||||
expect(decide({ ...base, getOnly: true })).toEqual({ action: 'send' });
|
||||
});
|
||||
test('--confirm <operationId>: an agent without a terminal sends a plain write, never an owner-only one', () => {
|
||||
const w = { ...base, kind: 'write' as const, method: 'PATCH', yes: true, tty: false, opId: 'appStoreVersions_updateInstance' };
|
||||
expect(decide({ ...w, confirm: 'appStoreVersions_updateInstance' })).toEqual({ action: 'send' });
|
||||
expect(decide({ ...w, confirm: 'appInfos_updateInstance' })).toMatchObject({ action: 'refuse', why: expect.stringContaining('does not equal') });
|
||||
expect(decide({ ...w, confirm: 'x', opId: undefined }).action).toBe('refuse');
|
||||
// still dry without --yes, still nothing under MCP / desktop
|
||||
expect(decide({ ...w, yes: false, confirm: w.opId }).action).toBe('dry');
|
||||
expect(decide({ ...w, agent: true, confirm: w.opId }).action).toBe('refuse');
|
||||
// owner-only: --confirm never replaces the owner's typed id, with or without a terminal
|
||||
const o = { ...w, kind: 'owner' as const, method: 'DELETE', opId: 'appScreenshots_deleteInstance' };
|
||||
expect(decide({ ...o, confirm: o.opId })).toMatchObject({ action: 'refuse', why: OWNER_NO_CONFIRM });
|
||||
expect(decide({ ...o, tty: true, confirm: o.opId })).toMatchObject({ action: 'refuse', why: OWNER_NO_CONFIRM });
|
||||
expect(decide({ ...o, tty: true })).toEqual({ action: 'confirm', typed: true });
|
||||
});
|
||||
test('the dry run shows the exact request without the credential', () => {
|
||||
const r = buildRequest(op('apple', 'appStoreVersions_updateInstance'), { id: '1' }, { data: { type: 'appStoreVersions', id: '1' } });
|
||||
const text = describeRequest(r);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue