@synoikia/core 0.16.0 → 0.17.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/dist/testing/compliance/config.d.ts +19 -0
- package/dist/testing/compliance/config.js +50 -0
- package/dist/testing/compliance/config.js.map +1 -0
- package/dist/testing/compliance/index.d.ts +5 -0
- package/dist/testing/compliance/index.js +3 -0
- package/dist/testing/compliance/index.js.map +1 -0
- package/dist/testing/compliance/profile.d.ts +62 -0
- package/dist/testing/compliance/profile.js +58 -0
- package/dist/testing/compliance/profile.js.map +1 -0
- package/dist/testing/compliance/run.d.ts +19 -0
- package/dist/testing/compliance/run.js +12 -0
- package/dist/testing/compliance/run.js.map +1 -0
- package/dist/testing/compliance/steps.d.ts +1 -0
- package/dist/testing/compliance/steps.js +465 -0
- package/dist/testing/compliance/steps.js.map +1 -0
- package/dist/testing/compliance/suite/access.feature +20 -0
- package/dist/testing/compliance/suite/catalog.feature +19 -0
- package/dist/testing/compliance/suite/connection-secrets.feature +10 -0
- package/dist/testing/compliance/suite/guides.feature +11 -0
- package/dist/testing/compliance/suite/lock-cases.feature +10 -0
- package/dist/testing/compliance/suite/locks.feature +21 -0
- package/dist/testing/compliance/suite/secrets.feature +24 -0
- package/dist/testing/compliance/verdict.d.ts +12 -0
- package/dist/testing/compliance/verdict.js +56 -0
- package/dist/testing/compliance/verdict.js.map +1 -0
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +1 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/repository.d.ts +2 -0
- package/dist/testing/repository.js +1 -1
- package/dist/testing/repository.js.map +1 -1
- package/package.json +26 -3
- package/dist/testing/contract.d.ts +0 -25
- package/dist/testing/contract.js +0 -81
- package/dist/testing/contract.js.map +0 -1
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { checkManifest, parsePluginSettings } from '@synoikia/plugin-sdk';
|
|
4
|
+
import * as quickpickle from 'quickpickle';
|
|
5
|
+
import { afterAll, inject } from 'vitest';
|
|
6
|
+
import { parse } from 'yaml';
|
|
7
|
+
import { startPluginHarness } from '../index.js';
|
|
8
|
+
import { startsAndAnswers } from '../repository.js';
|
|
9
|
+
import { loadProfile } from './profile.js';
|
|
10
|
+
import { currentRun, startRun } from './run.js';
|
|
11
|
+
import { FAILED_RULE } from './verdict.js';
|
|
12
|
+
let subject;
|
|
13
|
+
async function boot() {
|
|
14
|
+
const pluginDir = inject('synoikiaPluginDir');
|
|
15
|
+
const { profile, fake } = await loadProfile(pluginDir);
|
|
16
|
+
try {
|
|
17
|
+
const harness = await startPluginHarness({ pluginDir, connection: profile.connection }).catch(async (err) => {
|
|
18
|
+
throw new Error(`${FAILED_RULE}the plugin does not start: ${await startError(pluginDir, err)}`);
|
|
19
|
+
});
|
|
20
|
+
await harness.ctx.instances.update(harness.instanceId, {
|
|
21
|
+
settings: { executePerMinute: 10_000, writesPerMinute: 10_000 },
|
|
22
|
+
});
|
|
23
|
+
return { pluginDir, profile, fake, harness };
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
await fake?.close();
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Why the plugin did not start: what the bundle printed when it exited, as the release check shows it, on one line. */
|
|
31
|
+
async function startError(pluginDir, err) {
|
|
32
|
+
const manifest = JSON.parse(readFileSync(path.join(pluginDir, 'manifest.json'), 'utf8'));
|
|
33
|
+
try {
|
|
34
|
+
await startsAndAnswers(pluginDir, manifest.entry, 'the plugin');
|
|
35
|
+
}
|
|
36
|
+
catch (startErr) {
|
|
37
|
+
return startErr.message
|
|
38
|
+
.replace(/^the plugin does not start: /, '')
|
|
39
|
+
.split('\n')
|
|
40
|
+
.join(' / ');
|
|
41
|
+
}
|
|
42
|
+
return err instanceof Error ? err.message : String(err);
|
|
43
|
+
}
|
|
44
|
+
const subjectOf = () => (subject ??= boot());
|
|
45
|
+
// The feature files share one process (config.ts), and this file loads once for each of them. The first load
|
|
46
|
+
// registers the steps and owns the plugin; the last feature file to end stops it.
|
|
47
|
+
const firstLoad = !currentRun();
|
|
48
|
+
const run = startRun({
|
|
49
|
+
ended: 0,
|
|
50
|
+
subject: subjectOf,
|
|
51
|
+
async stop() {
|
|
52
|
+
const s = await subject?.catch(() => undefined);
|
|
53
|
+
await s?.harness.stop();
|
|
54
|
+
await s?.fake?.close();
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
const once = (define) => (firstLoad ? define : (() => undefined));
|
|
58
|
+
const Given = once(quickpickle.Given);
|
|
59
|
+
const When = once(quickpickle.When);
|
|
60
|
+
const Then = once(quickpickle.Then);
|
|
61
|
+
const Before = once(quickpickle.Before);
|
|
62
|
+
afterAll(async () => {
|
|
63
|
+
if (++run.ended === inject('synoikiaFeatureFiles'))
|
|
64
|
+
await run.stop();
|
|
65
|
+
});
|
|
66
|
+
// Feature files share the plugin, so each scenario starts with every group off and no operation level of its own.
|
|
67
|
+
Before(async () => {
|
|
68
|
+
const s = await subject?.catch(() => undefined);
|
|
69
|
+
if (!s)
|
|
70
|
+
return;
|
|
71
|
+
for (const op of s.harness.operations())
|
|
72
|
+
if (op.levelOverride !== null)
|
|
73
|
+
s.harness.setOperationLevel(op.key, null);
|
|
74
|
+
for (const group of new Set(s.harness.operations().map((o) => o.pluginGroup)))
|
|
75
|
+
s.harness.setGroupLevel(group, 'none');
|
|
76
|
+
await s.fake?.reset?.();
|
|
77
|
+
});
|
|
78
|
+
/** Fails the step with one line for each broken rule, as the verdict lists them. */
|
|
79
|
+
function report(issues) {
|
|
80
|
+
if (issues.length)
|
|
81
|
+
throw new Error(issues.map((i) => `${FAILED_RULE}${i}`).join('\n'));
|
|
82
|
+
}
|
|
83
|
+
const shared = new WeakMap();
|
|
84
|
+
const seen = (world) => {
|
|
85
|
+
let s = shared.get(world);
|
|
86
|
+
if (!s)
|
|
87
|
+
shared.set(world, (s = {}));
|
|
88
|
+
return s;
|
|
89
|
+
};
|
|
90
|
+
const syncIssues = (harness) => {
|
|
91
|
+
const status = harness.instance()?.lastSyncStatus;
|
|
92
|
+
return status === 'ok' ? [] : [`the catalog did not sync (${String(status)})`];
|
|
93
|
+
};
|
|
94
|
+
Given('core synced the catalog of the plugin', async () => {
|
|
95
|
+
report(syncIssues((await subjectOf()).harness));
|
|
96
|
+
});
|
|
97
|
+
When('core reads the manifest of the plugin', (world) => {
|
|
98
|
+
const manifest = JSON.parse(readFileSync(path.join(inject('synoikiaPluginDir'), 'manifest.json'), 'utf8'));
|
|
99
|
+
seen(world).manifestIssues = checkManifest(manifest);
|
|
100
|
+
});
|
|
101
|
+
Then('each secret field is write-only, uses the secret widget and is a sensitive key', (world) => {
|
|
102
|
+
report((seen(world).manifestIssues ?? []).filter((i) => i.startsWith('connection.') || i.startsWith('manifest:')));
|
|
103
|
+
});
|
|
104
|
+
Then('the manifest names at least one network host', (world) => {
|
|
105
|
+
report((seen(world).manifestIssues ?? []).filter((i) => i.startsWith('network.')));
|
|
106
|
+
});
|
|
107
|
+
Then('the profile has a case for each locked operation', async () => {
|
|
108
|
+
const { harness, profile } = await subjectOf();
|
|
109
|
+
const locked = harness.operations().filter((o) => o.locked && !o.stale);
|
|
110
|
+
report(locked.filter((o) => !profile.locks[o.key]).map((o) => `${o.key} is locked and the profile has no case for it`));
|
|
111
|
+
});
|
|
112
|
+
When('the agent reads the guide of each operation that requires one', async (world) => {
|
|
113
|
+
const { harness } = await subjectOf();
|
|
114
|
+
const issues = [];
|
|
115
|
+
for (const op of harness.operations().filter((o) => o.attestationRequired && !o.stale)) {
|
|
116
|
+
const read = await harness.search(`return await guides.get(${JSON.stringify(op.key)});`);
|
|
117
|
+
const content = read.ok ? read.value?.content : undefined;
|
|
118
|
+
if (typeof content !== 'string' || !content.trim())
|
|
119
|
+
issues.push(`the guide of ${op.key} is not provided`);
|
|
120
|
+
}
|
|
121
|
+
seen(world).guideIssues = issues;
|
|
122
|
+
});
|
|
123
|
+
Then('each guide has content', (world) => {
|
|
124
|
+
report(seen(world).guideIssues ?? []);
|
|
125
|
+
});
|
|
126
|
+
When('core starts the plugin', async () => {
|
|
127
|
+
await subjectOf();
|
|
128
|
+
});
|
|
129
|
+
Then('the catalog of the plugin has operations', async () => {
|
|
130
|
+
const { harness } = await subjectOf();
|
|
131
|
+
report(syncIssues(harness));
|
|
132
|
+
report(harness.operations().some((o) => !o.stale) ? [] : ['the catalog is empty']);
|
|
133
|
+
});
|
|
134
|
+
Then('each operation has a description', async () => {
|
|
135
|
+
const { harness } = await subjectOf();
|
|
136
|
+
const described = (docs) => ['summary', 'description'].some((k) => {
|
|
137
|
+
const text = docs?.[k];
|
|
138
|
+
return typeof text === 'string' && text.trim() !== '';
|
|
139
|
+
});
|
|
140
|
+
report(harness
|
|
141
|
+
.operations()
|
|
142
|
+
.filter((o) => !o.stale && !described(o.docs))
|
|
143
|
+
.map((o) => `${o.key} has no description`));
|
|
144
|
+
});
|
|
145
|
+
When('core reads the locks of plugin.yaml', async (world) => {
|
|
146
|
+
const { harness, pluginDir } = await subjectOf();
|
|
147
|
+
const file = path.join(pluginDir, 'plugin.yaml');
|
|
148
|
+
const settings = existsSync(file) ? parsePluginSettings(parse(readFileSync(file, 'utf8'))) : undefined;
|
|
149
|
+
const keys = new Set(harness
|
|
150
|
+
.operations()
|
|
151
|
+
.filter((o) => !o.stale)
|
|
152
|
+
.map((o) => o.key));
|
|
153
|
+
const named = (settings?.rules ?? [])
|
|
154
|
+
.filter((r) => r.locked)
|
|
155
|
+
.flatMap((r) => (Array.isArray(r.match) ? r.match : [r.match]))
|
|
156
|
+
.filter((m) => !m.includes('*'));
|
|
157
|
+
seen(world).lockIssues = named.filter((key) => !keys.has(key)).map((key) => `the lock ${key} names no operation`);
|
|
158
|
+
});
|
|
159
|
+
Then('each lock names an operation of the catalog', (world) => {
|
|
160
|
+
report(seen(world).lockIssues ?? []);
|
|
161
|
+
});
|
|
162
|
+
/** Sandbox code that makes one profile call through the plugin's binding. */
|
|
163
|
+
const codeOf = (h, call) => `return await ${h.manifest.binding.namespace}.${call.fn}(...${JSON.stringify(call.args)});`;
|
|
164
|
+
const label = (call) => `${call.fn}(${JSON.stringify(call.args).slice(1, -1)})`;
|
|
165
|
+
/** Sets the group of each call's operation; a call whose key is not in the catalog is an issue. */
|
|
166
|
+
function setGroups(h, calls, level) {
|
|
167
|
+
const issues = [];
|
|
168
|
+
for (const call of calls) {
|
|
169
|
+
if (!call.key)
|
|
170
|
+
issues.push(`${label(call)} names no operation key in the profile`);
|
|
171
|
+
else if (!h.operations().some((o) => o.key === call.key))
|
|
172
|
+
issues.push(`the catalog has no ${call.key}`);
|
|
173
|
+
else
|
|
174
|
+
h.setGroupLevel(h.operation(call.key).pluginGroup, level);
|
|
175
|
+
}
|
|
176
|
+
report(issues);
|
|
177
|
+
}
|
|
178
|
+
async function makeCalls(world, calls) {
|
|
179
|
+
const { harness } = await subjectOf();
|
|
180
|
+
const results = [];
|
|
181
|
+
for (const call of calls)
|
|
182
|
+
results.push({ call, result: await harness.execute(codeOf(harness, call)) });
|
|
183
|
+
seen(world).results = results;
|
|
184
|
+
}
|
|
185
|
+
const errorOf = (r) => (r.ok ? undefined : r.error);
|
|
186
|
+
Given('the groups of the sample reads are at level read', async () => {
|
|
187
|
+
const { harness, profile } = await subjectOf();
|
|
188
|
+
if (profile.reads.length === 0)
|
|
189
|
+
report(['the profile names no sample read']);
|
|
190
|
+
setGroups(harness, profile.reads, 'read');
|
|
191
|
+
});
|
|
192
|
+
Given('the groups of the sample writes are at level read', async () => {
|
|
193
|
+
const { harness, profile } = await subjectOf();
|
|
194
|
+
if (profile.writes.length === 0)
|
|
195
|
+
report(['the profile names no sample write']);
|
|
196
|
+
setGroups(harness, profile.writes, 'read');
|
|
197
|
+
});
|
|
198
|
+
When('the agent makes each sample read', async (world) => {
|
|
199
|
+
await makeCalls(world, (await subjectOf()).profile.reads);
|
|
200
|
+
});
|
|
201
|
+
When('the agent makes each sample write', async (world) => {
|
|
202
|
+
await makeCalls(world, (await subjectOf()).profile.writes);
|
|
203
|
+
});
|
|
204
|
+
When('the agent makes each call that the profile names as unknown', async (world) => {
|
|
205
|
+
const { profile } = await subjectOf();
|
|
206
|
+
if (profile.rejects.length === 0)
|
|
207
|
+
report(['the profile names no unknown call']);
|
|
208
|
+
await makeCalls(world, profile.rejects);
|
|
209
|
+
});
|
|
210
|
+
Then('each sample read returns a result', async (world) => {
|
|
211
|
+
const { harness } = await subjectOf();
|
|
212
|
+
report((seen(world).results ?? []).flatMap(({ call, result }) => {
|
|
213
|
+
if (!result.ok)
|
|
214
|
+
return [`${call.key} failed at level read (${JSON.stringify(errorOf(result))})`];
|
|
215
|
+
return harness.audit({ operationKey: call.key }).length ? [] : [`${call.key} ran but is not in the audit log`];
|
|
216
|
+
}));
|
|
217
|
+
});
|
|
218
|
+
Then('core refuses each sample write, because the operation is off', (world) => {
|
|
219
|
+
report((seen(world).results ?? []).flatMap(({ call, result }) => result.ok
|
|
220
|
+
? [`${call.key} ran at level read`]
|
|
221
|
+
: errorOf(result)?.code === 'OPERATION_DISABLED'
|
|
222
|
+
? []
|
|
223
|
+
: [`${call.key} failed at level read with ${JSON.stringify(errorOf(result))}, not because it is off`]));
|
|
224
|
+
});
|
|
225
|
+
Then('core refuses each of those calls', (world) => {
|
|
226
|
+
report((seen(world).results ?? []).flatMap(({ call, result }) => result.ok || errorOf(result)?.code !== 'UNKNOWN_OPERATION'
|
|
227
|
+
? [`the plugin accepted a call that is not in its catalog: ${label(call)}`]
|
|
228
|
+
: []));
|
|
229
|
+
});
|
|
230
|
+
const lockCases = (profile) => Object.entries(profile.locks).map(([key, c]) => ({ ...c, key }));
|
|
231
|
+
Given('the groups of the locked operations are at level write', async () => {
|
|
232
|
+
const { harness, profile } = await subjectOf();
|
|
233
|
+
setGroups(harness, lockCases(profile), 'write');
|
|
234
|
+
for (const c of lockCases(profile))
|
|
235
|
+
harness.setOperationLevel(c.key, null);
|
|
236
|
+
});
|
|
237
|
+
When('the agent makes the call of each lock case', async (world) => {
|
|
238
|
+
await makeCalls(world, lockCases((await subjectOf()).profile));
|
|
239
|
+
});
|
|
240
|
+
Then('core refuses each call, because the operation is off', async (world) => {
|
|
241
|
+
const { harness } = await subjectOf();
|
|
242
|
+
report((seen(world).results ?? []).flatMap(({ call, result }) => !harness.operation(call.key).locked || result.ok || errorOf(result)?.code !== 'OPERATION_DISABLED'
|
|
243
|
+
? [`${call.key} is not off by default`]
|
|
244
|
+
: []));
|
|
245
|
+
});
|
|
246
|
+
Given('each locked operation is at level ask', async () => {
|
|
247
|
+
const { harness, profile } = await subjectOf();
|
|
248
|
+
const cases = lockCases(profile);
|
|
249
|
+
setGroups(harness, cases, 'ask');
|
|
250
|
+
for (const c of cases)
|
|
251
|
+
harness.setOperationLevel(c.key, 'ask');
|
|
252
|
+
});
|
|
253
|
+
let lockRun;
|
|
254
|
+
/** Runs each lock case once for each feature file, as a human decides it: a wrong literal first, then the right one. */
|
|
255
|
+
async function approveLocks(world) {
|
|
256
|
+
seen(world).approvals = await (lockRun ??= runLocks());
|
|
257
|
+
}
|
|
258
|
+
async function runLocks() {
|
|
259
|
+
const { harness, profile } = await subjectOf();
|
|
260
|
+
setGroups(harness, lockCases(profile), 'ask');
|
|
261
|
+
for (const c of lockCases(profile))
|
|
262
|
+
harness.setOperationLevel(c.key, 'ask');
|
|
263
|
+
const approvals = [];
|
|
264
|
+
for (const c of lockCases(profile)) {
|
|
265
|
+
// Each case starts from the fake's seed: an earlier case may have changed what this one acts on.
|
|
266
|
+
await (await subjectOf()).fake?.reset?.();
|
|
267
|
+
const seenBy = { wrongRefused: false };
|
|
268
|
+
const result = await harness.execute(codeOf(harness, c), {
|
|
269
|
+
onApproval: (a) => {
|
|
270
|
+
seenBy.literal = a.pending.confirmLiteral;
|
|
271
|
+
seenBy.message = a.message;
|
|
272
|
+
seenBy.pending = JSON.stringify(a.pending);
|
|
273
|
+
try {
|
|
274
|
+
a.approve(`${c.confirm} (wrong)`);
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
seenBy.wrongRefused = true;
|
|
278
|
+
a.approve(c.confirm);
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
approvals.push({ key: c.key, confirm: c.confirm, target: c.target, wrongRefused: false, ...seenBy, result });
|
|
283
|
+
}
|
|
284
|
+
return approvals;
|
|
285
|
+
}
|
|
286
|
+
When('the agent makes the call of each lock case, and the human types a wrong literal and then the right one', approveLocks);
|
|
287
|
+
When('the agent makes the call of each lock case, and the human reads the approval', approveLocks);
|
|
288
|
+
Then('core refused the wrong literal and ran the call with the literal of its case', (world) => {
|
|
289
|
+
report((seen(world).approvals ?? []).flatMap((a) => {
|
|
290
|
+
if (a.literal !== a.confirm)
|
|
291
|
+
return [`${a.key} asks to type ${JSON.stringify(a.literal ?? null)} in place of ${JSON.stringify(a.confirm)}`];
|
|
292
|
+
if (!a.wrongRefused)
|
|
293
|
+
return [`${a.key} accepted a wrong confirmation literal`];
|
|
294
|
+
return a.result.ok ? [] : [`${a.key} failed after approval (${JSON.stringify(errorOf(a.result))})`];
|
|
295
|
+
}));
|
|
296
|
+
});
|
|
297
|
+
Then('the approval shows the target of each lock case', (world) => {
|
|
298
|
+
report((seen(world).approvals ?? []).flatMap((a) => {
|
|
299
|
+
if (a.message === undefined)
|
|
300
|
+
return [`${a.key} ran without an approval`];
|
|
301
|
+
if (!a.target)
|
|
302
|
+
return [`the lock case of ${a.key} names no target`];
|
|
303
|
+
return a.message.includes(a.target) ? [] : [`the approval of ${a.key} does not show ${JSON.stringify(a.target)}`];
|
|
304
|
+
}));
|
|
305
|
+
});
|
|
306
|
+
/** The secret values that must never be seen: those of the profile and the secret fields of the connection. */
|
|
307
|
+
const secretFields = ({ harness }) => Object.entries((harness.manifest.connection.schema.properties ?? {}))
|
|
308
|
+
.filter(([, p]) => p?.writeOnly)
|
|
309
|
+
.map(([name]) => name);
|
|
310
|
+
function secretValues(s) {
|
|
311
|
+
const { profile } = s;
|
|
312
|
+
const fromConnection = secretFields(s)
|
|
313
|
+
.map((name) => profile.connection[name])
|
|
314
|
+
.filter((v) => typeof v === 'string' && v !== '');
|
|
315
|
+
const values = [...profile.secrets.flatMap((s) => s.values), ...fromConnection];
|
|
316
|
+
report(values.filter((v) => typeof v !== 'string' || v === '').map(() => 'a secret value of the profile is empty'));
|
|
317
|
+
return [...new Set(values)];
|
|
318
|
+
}
|
|
319
|
+
const leaks = (text, values, where) => values
|
|
320
|
+
.filter((v) => text.includes(v))
|
|
321
|
+
.map((v) => `a secret value of the profile reached ${where}: "${v.slice(0, 4)}…"`);
|
|
322
|
+
Given('the groups of the secret reads are at level read', async () => {
|
|
323
|
+
const { harness, profile } = await subjectOf();
|
|
324
|
+
if (profile.secrets.length === 0)
|
|
325
|
+
report(['the profile names no secret read']);
|
|
326
|
+
setGroups(harness, profile.secrets, 'read');
|
|
327
|
+
});
|
|
328
|
+
When('the agent makes each secret read', async (world) => {
|
|
329
|
+
await makeCalls(world, (await subjectOf()).profile.secrets);
|
|
330
|
+
});
|
|
331
|
+
Then('no secret value of the profile reaches the agent or the audit log', async (world) => {
|
|
332
|
+
const s = await subjectOf();
|
|
333
|
+
const values = secretValues(s);
|
|
334
|
+
const results = seen(world).results ?? [];
|
|
335
|
+
report([
|
|
336
|
+
...results.flatMap(({ call, result }) => result.ok ? [] : [`${call.key} failed at level read (${JSON.stringify(errorOf(result))})`]),
|
|
337
|
+
...leaks(JSON.stringify(results.map((r) => r.result)), values, 'the agent'),
|
|
338
|
+
...leaks(JSON.stringify(s.harness.audit()), values, 'the audit log'),
|
|
339
|
+
]);
|
|
340
|
+
});
|
|
341
|
+
Given('the groups of the sample writes are at level ask', async () => {
|
|
342
|
+
const { harness, profile } = await subjectOf();
|
|
343
|
+
if (profile.writes.length === 0)
|
|
344
|
+
report(['the profile names no sample write']);
|
|
345
|
+
setGroups(harness, profile.writes, 'ask');
|
|
346
|
+
});
|
|
347
|
+
When('the agent makes each sample write, and the human reads the approval', async (world) => {
|
|
348
|
+
const { harness, profile } = await subjectOf();
|
|
349
|
+
const shown = [];
|
|
350
|
+
for (const call of profile.writes) {
|
|
351
|
+
const seenBy = { key: call.key };
|
|
352
|
+
await harness.execute(codeOf(harness, call), {
|
|
353
|
+
onApproval: (a) => {
|
|
354
|
+
seenBy.shown = `${a.message}\n${JSON.stringify(a.pending)}`;
|
|
355
|
+
a.deny();
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
shown.push(seenBy);
|
|
359
|
+
}
|
|
360
|
+
seen(world).writeApprovals = shown;
|
|
361
|
+
});
|
|
362
|
+
Then('no secret value of the profile reaches the approval', async (world) => {
|
|
363
|
+
const values = secretValues(await subjectOf());
|
|
364
|
+
const locks = await (lockRun ??= runLocks());
|
|
365
|
+
report([
|
|
366
|
+
...(seen(world).writeApprovals ?? []).flatMap((a) => a.shown === undefined
|
|
367
|
+
? [`${a.key ?? 'a sample write'} asked for no approval`]
|
|
368
|
+
: leaks(a.shown, values, `the approval of ${a.key ?? 'a sample write'}`)),
|
|
369
|
+
...locks.flatMap((a) => leaks(`${a.message ?? ''}\n${a.pending ?? ''}`, values, `the approval of ${a.key}`)),
|
|
370
|
+
]);
|
|
371
|
+
});
|
|
372
|
+
When('an admin tests the connection with the wrong credentials of the profile', async (world) => {
|
|
373
|
+
const s = await subjectOf();
|
|
374
|
+
const { harness, profile } = s;
|
|
375
|
+
if (!profile.connectionTest) {
|
|
376
|
+
// A connection with no secret field has no credentials that the upstream could refuse.
|
|
377
|
+
if (secretFields(s).length === 0)
|
|
378
|
+
return void (seen(world).connectionTest = { ok: false });
|
|
379
|
+
report(['the profile names no wrong credentials for the connection test']);
|
|
380
|
+
}
|
|
381
|
+
seen(world).connectionTest = await harness
|
|
382
|
+
.testConnection({ ...profile.connection, ...profile.connectionTest.wrong })
|
|
383
|
+
.catch((err) => ({ ok: false, message: String(err) }));
|
|
384
|
+
});
|
|
385
|
+
Then('the connection test fails', (world) => {
|
|
386
|
+
const result = seen(world).connectionTest;
|
|
387
|
+
report(result?.ok === false ? [] : ['the connection test passed with the wrong credentials of the profile']);
|
|
388
|
+
});
|
|
389
|
+
// ── Steps for a plugin's own feature files, on the named calls of the profile ──
|
|
390
|
+
const own = new WeakMap();
|
|
391
|
+
const ownOf = (world) => {
|
|
392
|
+
let o = own.get(world);
|
|
393
|
+
if (!o)
|
|
394
|
+
own.set(world, (o = {}));
|
|
395
|
+
return o;
|
|
396
|
+
};
|
|
397
|
+
async function namedCall(name) {
|
|
398
|
+
const s = await subjectOf();
|
|
399
|
+
const call = s.profile.calls[name];
|
|
400
|
+
if (!call)
|
|
401
|
+
throw new Error(`test/compliance.yaml names no call "${name}" under calls`);
|
|
402
|
+
return { ...s, call };
|
|
403
|
+
}
|
|
404
|
+
const LEVELS = ['none', 'read', 'ask', 'write'];
|
|
405
|
+
const levelOf = (level) => {
|
|
406
|
+
if (!LEVELS.includes(level))
|
|
407
|
+
throw new Error(`"${level}" is not one of ${LEVELS.join(', ')}`);
|
|
408
|
+
return level;
|
|
409
|
+
};
|
|
410
|
+
Given('the group of {string} is at level {word}', async (_world, name, level) => {
|
|
411
|
+
const { harness, call } = await namedCall(name);
|
|
412
|
+
if (!call.key)
|
|
413
|
+
throw new Error(`the call "${name}" names no operation key`);
|
|
414
|
+
harness.setGroupLevel(harness.operation(call.key).pluginGroup, levelOf(level));
|
|
415
|
+
});
|
|
416
|
+
Given('the operation of {string} is at level {word}', async (_world, name, level) => {
|
|
417
|
+
const { harness, call } = await namedCall(name);
|
|
418
|
+
if (!call.key)
|
|
419
|
+
throw new Error(`the call "${name}" names no operation key`);
|
|
420
|
+
harness.setOperationLevel(call.key, levelOf(level));
|
|
421
|
+
});
|
|
422
|
+
async function runNamed(world, name, decide) {
|
|
423
|
+
const { harness, call } = await namedCall(name);
|
|
424
|
+
const o = ownOf(world);
|
|
425
|
+
o.result = await harness.execute(codeOf(harness, call), {
|
|
426
|
+
onApproval: decide
|
|
427
|
+
? (a) => {
|
|
428
|
+
o.message = a.message;
|
|
429
|
+
o.literal = a.pending.confirmLiteral;
|
|
430
|
+
decide(a);
|
|
431
|
+
}
|
|
432
|
+
: undefined,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
When('the agent runs {string}', (world, name) => runNamed(world, name));
|
|
436
|
+
When('the agent runs {string}, and the human approves it', (world, name) => runNamed(world, name, (a) => a.approve()));
|
|
437
|
+
When('the agent runs {string}, and the human types {string}', (world, name, literal) => runNamed(world, name, (a) => a.approve(literal)));
|
|
438
|
+
When('the agent runs {string}, and the human denies it', (world, name) => runNamed(world, name, (a) => a.deny()));
|
|
439
|
+
Then('the agent gets a result that contains {string}', (world, text) => {
|
|
440
|
+
const { result } = ownOf(world);
|
|
441
|
+
if (!result?.ok)
|
|
442
|
+
throw new Error(`the call failed: ${JSON.stringify(result && errorOf(result))}`);
|
|
443
|
+
if (!JSON.stringify(result.value).includes(text))
|
|
444
|
+
throw new Error(`the result does not contain "${text}"`);
|
|
445
|
+
});
|
|
446
|
+
Then('core refuses the call with the code {string}', (world, code) => {
|
|
447
|
+
const { result } = ownOf(world);
|
|
448
|
+
if (result?.ok)
|
|
449
|
+
throw new Error('the call ran');
|
|
450
|
+
if (errorOf(result)?.code !== code)
|
|
451
|
+
throw new Error(`the call failed with ${JSON.stringify(errorOf(result))}`);
|
|
452
|
+
});
|
|
453
|
+
Then('the approval shows {string}', (world, text) => {
|
|
454
|
+
const { message } = ownOf(world);
|
|
455
|
+
if (message === undefined)
|
|
456
|
+
throw new Error('no approval was asked');
|
|
457
|
+
if (!message.includes(text))
|
|
458
|
+
throw new Error(`the approval "${message}" does not show "${text}"`);
|
|
459
|
+
});
|
|
460
|
+
Then('the approval asks to type {string}', (world, literal) => {
|
|
461
|
+
const { literal: asked } = ownOf(world);
|
|
462
|
+
if (asked !== literal)
|
|
463
|
+
throw new Error(`the approval asks to type ${JSON.stringify(asked ?? null)}`);
|
|
464
|
+
});
|
|
465
|
+
//# sourceMappingURL=steps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"steps.js","sourceRoot":"","sources":["../../../src/testing/compliance/steps.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
@id:compliance-access
|
|
2
|
+
Feature: Access levels
|
|
3
|
+
An admin sets the access level of each group of operations. Core reads at level read and runs a write only at level write or ask.
|
|
4
|
+
Core can do this only when the plugin classifies each operation correctly and refuses each call that is not in its catalog.
|
|
5
|
+
|
|
6
|
+
Rule: Access levels decide each call of the plugin
|
|
7
|
+
|
|
8
|
+
Scenario: Each sample read runs at level read
|
|
9
|
+
Given the groups of the sample reads are at level read
|
|
10
|
+
When the agent makes each sample read
|
|
11
|
+
Then each sample read returns a result
|
|
12
|
+
|
|
13
|
+
Scenario: Each sample write is off at level read
|
|
14
|
+
Given the groups of the sample writes are at level read
|
|
15
|
+
When the agent makes each sample write
|
|
16
|
+
Then core refuses each sample write, because the operation is off
|
|
17
|
+
|
|
18
|
+
Scenario: A call that is not in the catalog is refused
|
|
19
|
+
When the agent makes each call that the profile names as unknown
|
|
20
|
+
Then core refuses each of those calls
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
@id:compliance-catalog
|
|
2
|
+
Feature: A valid catalog
|
|
3
|
+
Core lists, classifies and describes each operation of the plugin from the catalog that the plugin syncs.
|
|
4
|
+
An admin sets the access level of an operation by its key, and an agent finds it by its description.
|
|
5
|
+
|
|
6
|
+
Rule: The plugin starts in core and syncs a valid catalog
|
|
7
|
+
|
|
8
|
+
Scenario: The plugin starts and syncs a catalog with operations
|
|
9
|
+
When core starts the plugin
|
|
10
|
+
Then the catalog of the plugin has operations
|
|
11
|
+
|
|
12
|
+
Scenario: Each operation has a description
|
|
13
|
+
Given core synced the catalog of the plugin
|
|
14
|
+
Then each operation has a description
|
|
15
|
+
|
|
16
|
+
Scenario: Each lock of plugin.yaml names an operation of the catalog
|
|
17
|
+
Given core synced the catalog of the plugin
|
|
18
|
+
When core reads the locks of plugin.yaml
|
|
19
|
+
Then each lock names an operation of the catalog
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
@id:compliance-connection-secrets
|
|
2
|
+
Feature: Connection secrets
|
|
3
|
+
An admin types a connection secret once. Core keeps it encrypted, never shows it again and keeps it out of results.
|
|
4
|
+
Core knows a secret field only from the manifest of the plugin.
|
|
5
|
+
|
|
6
|
+
Rule: The manifest marks each secret field of the connection
|
|
7
|
+
|
|
8
|
+
Scenario: Each secret field is write-only, hidden and sensitive
|
|
9
|
+
When core reads the manifest of the plugin
|
|
10
|
+
Then each secret field is write-only, uses the secret widget and is a sensitive key
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
@id:compliance-guides
|
|
2
|
+
Feature: Best-practice guides
|
|
3
|
+
An operation can require that the agent reads its guide before the agent calls it.
|
|
4
|
+
The plugin gives core the guide of each such operation.
|
|
5
|
+
|
|
6
|
+
Rule: The plugin provides the guide of each operation that requires one
|
|
7
|
+
|
|
8
|
+
Scenario: The agent reads the guide of each operation that requires one
|
|
9
|
+
Given core synced the catalog of the plugin
|
|
10
|
+
When the agent reads the guide of each operation that requires one
|
|
11
|
+
Then each guide has content
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
@id:compliance-lock-cases
|
|
2
|
+
Feature: A case for each locked operation
|
|
3
|
+
Core runs a locked operation only after a human types its confirmation.
|
|
4
|
+
The suite proves this for each locked operation, so the profile needs a case for each one.
|
|
5
|
+
|
|
6
|
+
Rule: The profile has a case for each locked operation of the catalog
|
|
7
|
+
|
|
8
|
+
Scenario: Each locked operation of the synced catalog has a case in the profile
|
|
9
|
+
Given core synced the catalog of the plugin
|
|
10
|
+
Then the profile has a case for each locked operation
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
@id:compliance-locks
|
|
2
|
+
Feature: Locked operations
|
|
3
|
+
A locked operation can delete or move data that core cannot restore. Core runs it only after a human types its confirmation.
|
|
4
|
+
The plugin locks the operation, names its target in the approval and gives core the literal to type.
|
|
5
|
+
|
|
6
|
+
Rule: A locked operation runs only with its typed confirmation
|
|
7
|
+
|
|
8
|
+
Scenario: Each locked operation is off at the level of its group
|
|
9
|
+
Given the groups of the locked operations are at level write
|
|
10
|
+
When the agent makes the call of each lock case
|
|
11
|
+
Then core refuses each call, because the operation is off
|
|
12
|
+
|
|
13
|
+
Scenario: Each locked operation asks to type the literal of its case
|
|
14
|
+
Given each locked operation is at level ask
|
|
15
|
+
When the agent makes the call of each lock case, and the human types a wrong literal and then the right one
|
|
16
|
+
Then core refused the wrong literal and ran the call with the literal of its case
|
|
17
|
+
|
|
18
|
+
Scenario: The approval of each locked operation names its target
|
|
19
|
+
Given each locked operation is at level ask
|
|
20
|
+
When the agent makes the call of each lock case, and the human reads the approval
|
|
21
|
+
Then the approval shows the target of each lock case
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
@id:compliance-secrets
|
|
2
|
+
Feature: Secrets stay hidden
|
|
3
|
+
Core redacts each secret that it knows before a result reaches the agent, the approver or the audit log.
|
|
4
|
+
Core knows a secret only when the plugin declares it, so a secret that the plugin does not declare can leak.
|
|
5
|
+
|
|
6
|
+
Rule: No secret reaches the agent, the approver or the audit log
|
|
7
|
+
|
|
8
|
+
Scenario: The secret values of the fake do not reach the agent
|
|
9
|
+
Given the groups of the secret reads are at level read
|
|
10
|
+
When the agent makes each secret read
|
|
11
|
+
Then no secret value of the profile reaches the agent or the audit log
|
|
12
|
+
|
|
13
|
+
Scenario: No secret value reaches the approver of a write
|
|
14
|
+
Given the groups of the sample writes are at level ask
|
|
15
|
+
When the agent makes each sample write, and the human reads the approval
|
|
16
|
+
Then no secret value of the profile reaches the approval
|
|
17
|
+
|
|
18
|
+
Scenario: The connection test refuses wrong credentials
|
|
19
|
+
When an admin tests the connection with the wrong credentials of the profile
|
|
20
|
+
Then the connection test fails
|
|
21
|
+
|
|
22
|
+
Scenario: The manifest names the hosts that the plugin connects to
|
|
23
|
+
When core reads the manifest of the plugin
|
|
24
|
+
Then the manifest names at least one network host
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Reporter, TestModule, Vitest } from 'vitest/node';
|
|
2
|
+
/** The line a failed step of the suite gives for each broken rule. */
|
|
3
|
+
export declare const FAILED_RULE = "Failed rule: ";
|
|
4
|
+
/** Prints core's verdict once the run ends: fit for production only when every scenario of the suite passed. */
|
|
5
|
+
export declare class VerdictReporter implements Reporter {
|
|
6
|
+
private readonly pluginDir;
|
|
7
|
+
private readonly suiteDir;
|
|
8
|
+
private vitest?;
|
|
9
|
+
constructor(pluginDir: string, suiteDir: string);
|
|
10
|
+
onInit(vitest: Vitest): void;
|
|
11
|
+
onTestRunEnd(testModules: ReadonlyArray<TestModule>): void;
|
|
12
|
+
}
|