principles-disciple 1.73.0 → 1.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALL.md +1 -3
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/core/event-log.ts +0 -9
- package/src/core/migration.ts +0 -1
- package/src/core/path-resolver.ts +0 -1
- package/src/core/paths.ts +0 -1
- package/src/hooks/gate-block-helper.ts +25 -20
- package/src/hooks/gate.ts +13 -61
- package/src/hooks/prompt.ts +1 -61
- package/src/types/event-types.ts +0 -1
- package/src/utils/io.ts +0 -22
- package/templates/langs/en/core/AGENTS.md +5 -5
- package/templates/langs/en/principles/THINKING_OS.md +3 -2
- package/templates/langs/en/skills/ai-sprint-orchestration/runtime/.gitignore +2 -2
- package/templates/langs/en/skills/evolve-task/SKILL.md +2 -2
- package/templates/langs/en/skills/pd-mentor/SKILL.md +1 -2
- package/templates/langs/zh/core/AGENTS.md +5 -5
- package/templates/langs/zh/principles/THINKING_OS.md +3 -2
- package/templates/langs/zh/skills/ai-sprint-orchestration/runtime/.gitignore +2 -2
- package/templates/langs/zh/skills/evolve-task/SKILL.md +2 -2
- package/templates/langs/zh/skills/pd-mentor/SKILL.md +1 -2
- package/tests/core/migration.test.ts +7 -7
- package/tests/core/path-resolver.test.ts +1 -1
- package/tests/core/paths-refactor.test.ts +0 -22
- package/tests/core/workspace-context.test.ts +2 -2
- package/tests/core-anti-growth.test.ts +0 -1
- package/tests/hooks/confirm-first-removal.test.ts +188 -0
- package/tests/hooks/gate-no-path-write-tool.test.ts +172 -0
- package/src/core/confirm-first-gate.ts +0 -255
- package/templates/langs/en/skills/plan-script/SKILL.md +0 -32
- package/templates/langs/zh/skills/plan-script/SKILL.md +0 -32
- package/tests/hooks/confirm-first-gate.test.ts +0 -333
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: plan-script
|
|
3
|
-
description: Create a step-by-step movie-script style execution plan. Includes target files, verification metrics, and rollback strategy.
|
|
4
|
-
disable-model-invocation: true
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Plan Script
|
|
8
|
-
|
|
9
|
-
**Goal**: Produce a "foolproof" executable plan to ensure controlled execution.
|
|
10
|
-
|
|
11
|
-
Please generate plan in the following structure:
|
|
12
|
-
|
|
13
|
-
## 1. Target Files (Authorization List)
|
|
14
|
-
- List file paths **uniquely authorized** for modification in this plan.
|
|
15
|
-
- Format: `- path/to/file`
|
|
16
|
-
|
|
17
|
-
## 2. Steps (Execution Steps)
|
|
18
|
-
1. Operations specific to filenames and tool calls.
|
|
19
|
-
2. Each step includes expected intermediate state.
|
|
20
|
-
|
|
21
|
-
## 3. Metrics (Verification Metrics)
|
|
22
|
-
- How to quantitatively prove this plan succeeded? (e.g., tests pass, command returns 0, specific string appears in logs).
|
|
23
|
-
|
|
24
|
-
## 4. Active Mental Models
|
|
25
|
-
- Select exactly **2** meta-cognitive models from `.principles/THINKING_OS.md` that are most relevant to the current task.
|
|
26
|
-
- Format: `- [T-0X] Model Name: Why is it needed for this specific task?`
|
|
27
|
-
|
|
28
|
-
## 5. Rollback (Rollback Strategy)
|
|
29
|
-
- If step 2 fails, how to one-click restore to safe state?
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
**Action**: Update above content to `PLAN.md` and set `STATUS: READY`.
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: plan-script
|
|
3
|
-
description: Create a step-by-step movie-script style execution plan. Includes target files, verification metrics, and rollback strategy.
|
|
4
|
-
disable-model-invocation: true
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Plan Script (计划编排)
|
|
8
|
-
|
|
9
|
-
**目标**: 产生一份“傻瓜式”可执行计划,确保执行过程受控。
|
|
10
|
-
|
|
11
|
-
请按以下结构生成计划:
|
|
12
|
-
|
|
13
|
-
## 1. Target Files (授权清单)
|
|
14
|
-
- 列出本次计划**唯一授权**修改的文件路径。
|
|
15
|
-
- 格式:`- path/to/file`
|
|
16
|
-
|
|
17
|
-
## 2. Steps (执行步骤)
|
|
18
|
-
1. 具体到文件名和工具调用的操作。
|
|
19
|
-
2. 每个步骤包含预期的中间状态。
|
|
20
|
-
|
|
21
|
-
## 3. Metrics (验证指标)
|
|
22
|
-
- 如何量化证明本计划成功了?(如:测试通过、命令返回 0、日志出现特定字符串)。
|
|
23
|
-
|
|
24
|
-
## 4. Active Mental Models (激活的思维模型)
|
|
25
|
-
- 从 `.principles/THINKING_OS.md` 中挑选 **2 个** 最适合当前任务的元认知模型。
|
|
26
|
-
- 格式:`- [T-0X] 模型名称:为什么在这个任务中需要它?`
|
|
27
|
-
|
|
28
|
-
## 5. Rollback (回滚方案)
|
|
29
|
-
- 如果步骤 2 失败,如何一键恢复到安全状态?
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
**动作**: 请将以上内容更新至 `PLAN.md`,并设置 `STATUS: READY`。
|
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import * as os from 'os';
|
|
3
|
-
import * as path from 'path';
|
|
4
|
-
import * as fs from 'fs';
|
|
5
|
-
import {
|
|
6
|
-
evaluateConfirmFirstGateSync,
|
|
7
|
-
detectApprovalMarker,
|
|
8
|
-
setConfirmFirstDirective,
|
|
9
|
-
setConfirmFirstApproval,
|
|
10
|
-
resetConfirmFirst,
|
|
11
|
-
isSessionApproved,
|
|
12
|
-
hasActiveDirective,
|
|
13
|
-
clearAllConfirmFirstState,
|
|
14
|
-
setConfirmFirstStore,
|
|
15
|
-
hydrateFromStore,
|
|
16
|
-
} from '../../src/core/confirm-first-gate.js';
|
|
17
|
-
import { SqliteConnection } from '@principles/core/runtime-v2';
|
|
18
|
-
import { SqliteConfirmFirstStateStore } from '@principles/core/runtime-v2';
|
|
19
|
-
|
|
20
|
-
describe('Confirm-First Gate', () => {
|
|
21
|
-
beforeEach(() => {
|
|
22
|
-
clearAllConfirmFirstState();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('detectApprovalMarker', () => {
|
|
26
|
-
it('detects Chinese approval markers', () => {
|
|
27
|
-
expect(detectApprovalMarker('确认')).toBe(true);
|
|
28
|
-
expect(detectApprovalMarker('批准')).toBe(true);
|
|
29
|
-
expect(detectApprovalMarker('按计划执行')).toBe(true);
|
|
30
|
-
expect(detectApprovalMarker('可以执行')).toBe(true);
|
|
31
|
-
expect(detectApprovalMarker('就这么做')).toBe(true);
|
|
32
|
-
expect(detectApprovalMarker('去执行')).toBe(true);
|
|
33
|
-
expect(detectApprovalMarker('开始执行')).toBe(true);
|
|
34
|
-
expect(detectApprovalMarker('执行吧')).toBe(true);
|
|
35
|
-
expect(detectApprovalMarker('同意')).toBe(true);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('detects English approval markers', () => {
|
|
39
|
-
expect(detectApprovalMarker('approved')).toBe(true);
|
|
40
|
-
expect(detectApprovalMarker('go ahead')).toBe(true);
|
|
41
|
-
expect(detectApprovalMarker('lgtm')).toBe(true);
|
|
42
|
-
expect(detectApprovalMarker('yes, do it')).toBe(true);
|
|
43
|
-
expect(detectApprovalMarker('do it')).toBe(true);
|
|
44
|
-
expect(detectApprovalMarker('yes, proceed')).toBe(true);
|
|
45
|
-
expect(detectApprovalMarker('yes, execute')).toBe(true);
|
|
46
|
-
expect(detectApprovalMarker('proceed with the plan')).toBe(true);
|
|
47
|
-
expect(detectApprovalMarker('execute the plan')).toBe(true);
|
|
48
|
-
expect(detectApprovalMarker('please proceed with the plan')).toBe(true);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('rejects vague text', () => {
|
|
52
|
-
expect(detectApprovalMarker('看看')).toBe(false);
|
|
53
|
-
expect(detectApprovalMarker('继续想想')).toBe(false);
|
|
54
|
-
expect(detectApprovalMarker('你决定')).toBe(false);
|
|
55
|
-
expect(detectApprovalMarker('hello world')).toBe(false);
|
|
56
|
-
expect(detectApprovalMarker('')).toBe(false);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('rejects negated Chinese approval', () => {
|
|
60
|
-
expect(detectApprovalMarker('不同意')).toBe(false);
|
|
61
|
-
expect(detectApprovalMarker('不确认')).toBe(false);
|
|
62
|
-
expect(detectApprovalMarker('先不执行')).toBe(false);
|
|
63
|
-
expect(detectApprovalMarker('还没准备好确认')).toBe(false);
|
|
64
|
-
expect(detectApprovalMarker('暂不批准')).toBe(false);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('rejects negated English approval', () => {
|
|
68
|
-
expect(detectApprovalMarker("don't proceed")).toBe(false);
|
|
69
|
-
expect(detectApprovalMarker("don't do it")).toBe(false);
|
|
70
|
-
expect(detectApprovalMarker("not ready to confirm")).toBe(false);
|
|
71
|
-
expect(detectApprovalMarker("can't approve yet")).toBe(false);
|
|
72
|
-
expect(detectApprovalMarker("won't proceed")).toBe(false);
|
|
73
|
-
expect(detectApprovalMarker("stop")).toBe(false);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('rejects ambiguous English phrases without explicit approval context', () => {
|
|
77
|
-
expect(detectApprovalMarker('please confirm requirements before proceeding')).toBe(false);
|
|
78
|
-
expect(detectApprovalMarker('how should we proceed?')).toBe(false);
|
|
79
|
-
expect(detectApprovalMarker('confirm the requirement first')).toBe(false);
|
|
80
|
-
expect(detectApprovalMarker('should I proceed?')).toBe(false);
|
|
81
|
-
expect(detectApprovalMarker('I need to confirm something')).toBe(false);
|
|
82
|
-
expect(detectApprovalMarker('let me confirm the plan')).toBe(false);
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
describe('evaluateConfirmFirstGateSync', () => {
|
|
87
|
-
it('skips when no sessionId', () => {
|
|
88
|
-
const result = evaluateConfirmFirstGateSync(undefined, 'write', {});
|
|
89
|
-
expect(result.action).toBe('skip');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('skips when no confirm-first directive active', () => {
|
|
93
|
-
const result = evaluateConfirmFirstGateSync('session-1', 'write', {});
|
|
94
|
-
expect(result.action).toBe('skip');
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('allows non-mutating tools even with active directive', () => {
|
|
98
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
99
|
-
const result = evaluateConfirmFirstGateSync('session-1', 'read', {});
|
|
100
|
-
expect(result.action).toBe('allow');
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('blocks write tool when directive active and not approved', () => {
|
|
104
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
105
|
-
const result = evaluateConfirmFirstGateSync('session-1', 'write', { path: 'test.json' });
|
|
106
|
-
expect(result.action).toBe('block');
|
|
107
|
-
expect(result.reason).toBe('confirm_first_required');
|
|
108
|
-
expect(result.principleId).toBe('princ-mvp-acceptance-confirm-first');
|
|
109
|
-
expect(result.nextAction).toContain('owner approval');
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('blocks edit tool when directive active and not approved', () => {
|
|
113
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
114
|
-
const result = evaluateConfirmFirstGateSync('session-1', 'edit', { file_path: 'test.ts' });
|
|
115
|
-
expect(result.action).toBe('block');
|
|
116
|
-
expect(result.reason).toBe('confirm_first_required');
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('blocks delete_file when directive active and not approved', () => {
|
|
120
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
121
|
-
const result = evaluateConfirmFirstGateSync('session-1', 'delete_file', { path: 'test.txt' });
|
|
122
|
-
expect(result.action).toBe('block');
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('blocks mutating exec when directive active and not approved', () => {
|
|
126
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
127
|
-
const result = evaluateConfirmFirstGateSync('session-1', 'exec', { command: 'rm -rf /tmp/test' });
|
|
128
|
-
expect(result.action).toBe('block');
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('allows non-mutating exec when directive active and not approved', () => {
|
|
132
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
133
|
-
const result = evaluateConfirmFirstGateSync('session-1', 'exec', { command: 'ls -la' });
|
|
134
|
-
expect(result.action).toBe('allow');
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('allows bash with undefined params when directive active', () => {
|
|
138
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
139
|
-
const result = evaluateConfirmFirstGateSync('session-1', 'bash', undefined);
|
|
140
|
-
expect(result.action).toBe('allow');
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('allows read tool when directive active and not approved', () => {
|
|
144
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
145
|
-
const result = evaluateConfirmFirstGateSync('session-1', 'read', { file_path: 'test.ts' });
|
|
146
|
-
expect(result.action).toBe('allow');
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('allows write after approval', () => {
|
|
150
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
151
|
-
setConfirmFirstApproval('session-1');
|
|
152
|
-
const result = evaluateConfirmFirstGateSync('session-1', 'write', { path: 'test.json' });
|
|
153
|
-
expect(result.action).toBe('allow');
|
|
154
|
-
expect(isSessionApproved('session-1')).toBe(true);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('approval is session-scoped', () => {
|
|
158
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
159
|
-
setConfirmFirstDirective('session-2', true, 'princ-mvp-acceptance-confirm-first');
|
|
160
|
-
setConfirmFirstApproval('session-1');
|
|
161
|
-
|
|
162
|
-
expect(evaluateConfirmFirstGateSync('session-1', 'write', {}).action).toBe('allow');
|
|
163
|
-
expect(evaluateConfirmFirstGateSync('session-2', 'write', {}).action).toBe('block');
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('blocks apply_patch with no path when directive active', () => {
|
|
167
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
168
|
-
const result = evaluateConfirmFirstGateSync('session-1', 'apply_patch', { patch: '@@ -1 +1 @@\n-old\n+new' });
|
|
169
|
-
expect(result.action).toBe('block');
|
|
170
|
-
expect(result.reason).toBe('confirm_first_required');
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it('allows apply_patch after approval', () => {
|
|
174
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
175
|
-
setConfirmFirstApproval('session-1');
|
|
176
|
-
const result = evaluateConfirmFirstGateSync('session-1', 'apply_patch', { patch: '@@ -1 +1 @@\n-old\n+new' });
|
|
177
|
-
expect(result.action).toBe('allow');
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('reset clears both directive and approval state', () => {
|
|
181
|
-
setConfirmFirstDirective('session-1', true, 'princ-mvp-acceptance-confirm-first');
|
|
182
|
-
setConfirmFirstApproval('session-1');
|
|
183
|
-
resetConfirmFirst('session-1');
|
|
184
|
-
|
|
185
|
-
expect(hasActiveDirective('session-1')).toBe(false);
|
|
186
|
-
expect(isSessionApproved('session-1')).toBe(false);
|
|
187
|
-
expect(evaluateConfirmFirstGateSync('session-1', 'write', {}).action).toBe('skip');
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
describe('Cross-restart persistence', () => {
|
|
193
|
-
let tmpDir: string;
|
|
194
|
-
let connection: SqliteConnection;
|
|
195
|
-
let store: SqliteConfirmFirstStateStore;
|
|
196
|
-
|
|
197
|
-
beforeEach(() => {
|
|
198
|
-
clearAllConfirmFirstState();
|
|
199
|
-
setConfirmFirstStore(null);
|
|
200
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pd-cf-test-'));
|
|
201
|
-
connection = new SqliteConnection(tmpDir);
|
|
202
|
-
store = new SqliteConfirmFirstStateStore(connection);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
afterEach(() => {
|
|
206
|
-
setConfirmFirstStore(null);
|
|
207
|
-
clearAllConfirmFirstState();
|
|
208
|
-
try {
|
|
209
|
-
connection.close();
|
|
210
|
-
} catch {}
|
|
211
|
-
try {
|
|
212
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
213
|
-
} catch {}
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('directive + approval survive restart', () => {
|
|
217
|
-
setConfirmFirstStore(store);
|
|
218
|
-
setConfirmFirstDirective('sess-restart', true, 'princ-123');
|
|
219
|
-
setConfirmFirstApproval('sess-restart');
|
|
220
|
-
|
|
221
|
-
expect(evaluateConfirmFirstGateSync('sess-restart', 'write', {}).action).toBe('allow');
|
|
222
|
-
|
|
223
|
-
setConfirmFirstStore(null);
|
|
224
|
-
clearAllConfirmFirstState();
|
|
225
|
-
setConfirmFirstStore(store);
|
|
226
|
-
hydrateFromStore('sess-restart');
|
|
227
|
-
|
|
228
|
-
expect(evaluateConfirmFirstGateSync('sess-restart', 'write', {}).action).toBe('allow');
|
|
229
|
-
expect(hasActiveDirective('sess-restart')).toBe(true);
|
|
230
|
-
expect(isSessionApproved('sess-restart')).toBe(true);
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it('directive without approval survives restart', () => {
|
|
234
|
-
setConfirmFirstStore(store);
|
|
235
|
-
setConfirmFirstDirective('sess-restart', true, 'princ-456');
|
|
236
|
-
|
|
237
|
-
expect(evaluateConfirmFirstGateSync('sess-restart', 'write', {}).action).toBe('block');
|
|
238
|
-
|
|
239
|
-
setConfirmFirstStore(null);
|
|
240
|
-
clearAllConfirmFirstState();
|
|
241
|
-
setConfirmFirstStore(store);
|
|
242
|
-
hydrateFromStore('sess-restart');
|
|
243
|
-
|
|
244
|
-
expect(evaluateConfirmFirstGateSync('sess-restart', 'write', {}).action).toBe('block');
|
|
245
|
-
expect(hasActiveDirective('sess-restart')).toBe(true);
|
|
246
|
-
expect(isSessionApproved('sess-restart')).toBe(false);
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
it('no directive survives restart', () => {
|
|
250
|
-
setConfirmFirstStore(store);
|
|
251
|
-
|
|
252
|
-
setConfirmFirstStore(null);
|
|
253
|
-
clearAllConfirmFirstState();
|
|
254
|
-
setConfirmFirstStore(store);
|
|
255
|
-
hydrateFromStore('sess-noexist');
|
|
256
|
-
|
|
257
|
-
expect(evaluateConfirmFirstGateSync('sess-noexist', 'write', {}).action).toBe('skip');
|
|
258
|
-
expect(hasActiveDirective('sess-noexist')).toBe(false);
|
|
259
|
-
});
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
describe('Store degradation (ERR-002)', () => {
|
|
263
|
-
afterEach(() => {
|
|
264
|
-
setConfirmFirstStore(null);
|
|
265
|
-
clearAllConfirmFirstState();
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it('store write failure degrades gracefully to cache-only', () => {
|
|
269
|
-
const throwingStore = {
|
|
270
|
-
upsertDirective: () => { throw new Error('DB unavailable'); },
|
|
271
|
-
upsertApproval: () => { throw new Error('DB unavailable'); },
|
|
272
|
-
getState: () => null,
|
|
273
|
-
deleteState: () => { throw new Error('DB unavailable'); },
|
|
274
|
-
deleteAllState: () => { throw new Error('DB unavailable'); },
|
|
275
|
-
pruneStaleRows: () => 0,
|
|
276
|
-
getAllState: () => [],
|
|
277
|
-
} as unknown as SqliteConfirmFirstStateStore;
|
|
278
|
-
|
|
279
|
-
setConfirmFirstStore(throwingStore);
|
|
280
|
-
setConfirmFirstDirective('sess-degrade', true, 'princ-123');
|
|
281
|
-
|
|
282
|
-
expect(hasActiveDirective('sess-degrade')).toBe(true);
|
|
283
|
-
|
|
284
|
-
setConfirmFirstApproval('sess-degrade');
|
|
285
|
-
expect(isSessionApproved('sess-degrade')).toBe(true);
|
|
286
|
-
expect(evaluateConfirmFirstGateSync('sess-degrade', 'write', {}).action).toBe('allow');
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
describe('Stale directive cleared on reset (PRI-266)', () => {
|
|
291
|
-
beforeEach(() => {
|
|
292
|
-
clearAllConfirmFirstState();
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
it('resetConfirmFirst clears directive and approval from cache and store', () => {
|
|
296
|
-
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pd-cf-stale-'));
|
|
297
|
-
try {
|
|
298
|
-
const connection = new SqliteConnection(tmpDir);
|
|
299
|
-
const store = new SqliteConfirmFirstStateStore(connection);
|
|
300
|
-
setConfirmFirstStore(store);
|
|
301
|
-
|
|
302
|
-
setConfirmFirstDirective('sess-stale', true, 'princ-stale');
|
|
303
|
-
setConfirmFirstApproval('sess-stale');
|
|
304
|
-
|
|
305
|
-
expect(hasActiveDirective('sess-stale')).toBe(true);
|
|
306
|
-
expect(isSessionApproved('sess-stale')).toBe(true);
|
|
307
|
-
|
|
308
|
-
resetConfirmFirst('sess-stale');
|
|
309
|
-
|
|
310
|
-
expect(hasActiveDirective('sess-stale')).toBe(false);
|
|
311
|
-
expect(isSessionApproved('sess-stale')).toBe(false);
|
|
312
|
-
expect(evaluateConfirmFirstGateSync('sess-stale', 'write', {}).action).toBe('skip');
|
|
313
|
-
|
|
314
|
-
connection.close();
|
|
315
|
-
} finally {
|
|
316
|
-
setConfirmFirstStore(null);
|
|
317
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it('resetConfirmFirst without store clears in-memory cache only', () => {
|
|
322
|
-
setConfirmFirstDirective('sess-nostore', true, 'princ-nostore');
|
|
323
|
-
setConfirmFirstApproval('sess-nostore');
|
|
324
|
-
|
|
325
|
-
expect(hasActiveDirective('sess-nostore')).toBe(true);
|
|
326
|
-
expect(isSessionApproved('sess-nostore')).toBe(true);
|
|
327
|
-
|
|
328
|
-
resetConfirmFirst('sess-nostore');
|
|
329
|
-
|
|
330
|
-
expect(hasActiveDirective('sess-nostore')).toBe(false);
|
|
331
|
-
expect(isSessionApproved('sess-nostore')).toBe(false);
|
|
332
|
-
});
|
|
333
|
-
});
|