finish-complete-apply-kn-b.test.mjs
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6
docs: record AIP-b SD-21 land (KN #308)
Human
9 days ago
| 1 | /** |
| 2 | * FINISH-COMPLETE-APPLY-KN-b — seven-tier coverage (§FCA.7). |
| 3 | * Frozen: ~/scooling/docs/FINISH-COMPLETE-APPLY-CONTRACT.md |
| 4 | * |
| 5 | * Tiers: unit · integration · e2e · stress · data-integrity · performance · security |
| 6 | */ |
| 7 | |
| 8 | import { describe, it, beforeEach, afterEach } from 'node:test'; |
| 9 | import assert from 'node:assert/strict'; |
| 10 | import fs from 'node:fs'; |
| 11 | import path from 'node:path'; |
| 12 | import { performance } from 'node:perf_hooks'; |
| 13 | import { fileURLToPath } from 'node:url'; |
| 14 | import { |
| 15 | personalSelfApplyRefusalReason, |
| 16 | isPersonalSelfApplyClass, |
| 17 | matchesScoolingTaskFingerprint, |
| 18 | matchesScoolingMediaFingerprint, |
| 19 | isAdmittedSeamSelfApplyFingerprint, |
| 20 | applyPersonalSelfApplyEvaluationE1, |
| 21 | SCOOLING_TASK_EXTERNAL_REF_RE, |
| 22 | SCOOLING_MEDIA_EXTERNAL_REF_RE, |
| 23 | SCOOLING_REVIEW_TRAY_INTENT, |
| 24 | } from '../lib/hub-proposal-personal-self-apply.mjs'; |
| 25 | import { |
| 26 | resolveOptionalScoolingExternalRef, |
| 27 | readProposeExternalRefRaw, |
| 28 | } from '../lib/scooling-external-ref.mjs'; |
| 29 | import { TASK_PROPOSAL_SOURCE, handleTaskProposeRequest } from '../lib/task/task-write.mjs'; |
| 30 | import { MEDIA_PROPOSAL_SOURCE, handleMediaLinkProposeRequest } from '../lib/attachments/attachment-write.mjs'; |
| 31 | import { DELEGATION_PROPOSAL_SOURCE } from '../lib/agent/delegation.mjs'; |
| 32 | import { FLOW_PROPOSAL_SOURCE } from '../lib/flow/flow-authoring.mjs'; |
| 33 | import { createProposal, getProposal } from '../hub/proposals-store.mjs'; |
| 34 | import { stripClientEvaluationFields } from '../lib/hub-proposal-create-augment.mjs'; |
| 35 | import { sampleTaskCreatePayload } from './fixtures/task/write-helpers.mjs'; |
| 36 | import { |
| 37 | buildMediaWriteFixture, |
| 38 | grantActiveConsent, |
| 39 | sampleLinkProposeBody, |
| 40 | } from './fixtures/media/write-helpers.mjs'; |
| 41 | import { FM_PROPOSAL_SOURCE, FM_TASK_PROPOSAL_KIND } from '../lib/task/task-hosted-proposal.mjs'; |
| 42 | |
| 43 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
| 44 | const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-finish-complete-apply-kn-b'); |
| 45 | |
| 46 | const ACTOR = 'google:learner-a'; |
| 47 | const OTHER = 'google:learner-b'; |
| 48 | |
| 49 | /** |
| 50 | * Enable media external-link propose for FCA fixtures (§FCA.7 media rows). |
| 51 | * @param {string} dataDir |
| 52 | */ |
| 53 | function enableMediaExternalLinkWrites(dataDir) { |
| 54 | fs.mkdirSync(dataDir, { recursive: true }); |
| 55 | fs.writeFileSync( |
| 56 | path.join(dataDir, 'hub_media_write_policy.json'), |
| 57 | JSON.stringify({ media_external_link_enabled: true, media_attach_enabled: true }), |
| 58 | 'utf8', |
| 59 | ); |
| 60 | } |
| 61 | |
| 62 | function taskProposal(overrides = {}) { |
| 63 | const proposalId = overrides.proposal_id || 'prop-task-1'; |
| 64 | const bodyObj = overrides.bodyObj || { |
| 65 | proposal_kind: 'task_create', |
| 66 | task: { |
| 67 | schema: 'knowtation.task/v0', |
| 68 | task_id: 'task_fca_1', |
| 69 | kind: 'personal', |
| 70 | scope: 'personal', |
| 71 | status: 'pending', |
| 72 | title: 'FCA', |
| 73 | workspace_id: 'ws', |
| 74 | }, |
| 75 | }; |
| 76 | return { |
| 77 | proposal_id: proposalId, |
| 78 | status: 'proposed', |
| 79 | source: TASK_PROPOSAL_SOURCE, |
| 80 | path: `meta/tasks/proposals/${proposalId}.json`, |
| 81 | external_ref: 'scooling.task:fixture-001', |
| 82 | body: JSON.stringify(bodyObj), |
| 83 | frontmatter: { |
| 84 | [FM_PROPOSAL_SOURCE]: TASK_PROPOSAL_SOURCE, |
| 85 | [FM_TASK_PROPOSAL_KIND]: bodyObj.proposal_kind, |
| 86 | }, |
| 87 | task_meta: { |
| 88 | record_kind: 'task', |
| 89 | proposal_kind: bodyObj.proposal_kind, |
| 90 | task_id: bodyObj.task?.task_id ?? null, |
| 91 | }, |
| 92 | ...overrides, |
| 93 | }; |
| 94 | } |
| 95 | |
| 96 | function mediaProposal(overrides = {}) { |
| 97 | const proposalId = overrides.proposal_id || 'prop-media-1'; |
| 98 | const bodyObj = overrides.bodyObj || { |
| 99 | proposal_kind: 'media_external_link', |
| 100 | scope: 'personal', |
| 101 | connector_id: 'ext_drive', |
| 102 | opaque_ref: 'file:abc', |
| 103 | consent_id: 'consent_1', |
| 104 | attachment_id: 'att_1', |
| 105 | }; |
| 106 | return { |
| 107 | proposal_id: proposalId, |
| 108 | status: 'proposed', |
| 109 | source: MEDIA_PROPOSAL_SOURCE, |
| 110 | path: `meta/media/proposals/${proposalId}.json`, |
| 111 | external_ref: 'scooling.media:fixture-001', |
| 112 | body: JSON.stringify(bodyObj), |
| 113 | media_meta: { proposal_kind: bodyObj.proposal_kind, record_kind: 'media_external_link' }, |
| 114 | ...overrides, |
| 115 | }; |
| 116 | } |
| 117 | |
| 118 | function eligible(proposal, extra = {}) { |
| 119 | return { |
| 120 | proposal, |
| 121 | hasVaultWrite: true, |
| 122 | partitionOwned: true, |
| 123 | role: 'member', |
| 124 | humanActor: true, |
| 125 | tokenType: null, |
| 126 | actorKind: 'human', |
| 127 | sessionBound: true, |
| 128 | authorActorId: ACTOR, |
| 129 | approverActorId: ACTOR, |
| 130 | ...extra, |
| 131 | }; |
| 132 | } |
| 133 | |
| 134 | describe('FINISH-COMPLETE-APPLY-KN-b unit — admission predicate §FCA.4', () => { |
| 135 | it('admits personal task_create + media_external_link fingerprints', () => { |
| 136 | assert.equal(matchesScoolingTaskFingerprint(taskProposal()), true); |
| 137 | assert.equal(matchesScoolingMediaFingerprint(mediaProposal()), true); |
| 138 | assert.equal(personalSelfApplyRefusalReason(eligible(taskProposal())), null); |
| 139 | assert.equal(personalSelfApplyRefusalReason(eligible(mediaProposal())), null); |
| 140 | }); |
| 141 | |
| 142 | it('refuses Delegation unconditionally; Flow not admitted', () => { |
| 143 | assert.equal( |
| 144 | personalSelfApplyRefusalReason( |
| 145 | eligible({ status: 'proposed', source: DELEGATION_PROPOSAL_SOURCE }), |
| 146 | ), |
| 147 | 'SELF_APPLY_DELEGATION_REFUSED', |
| 148 | ); |
| 149 | assert.equal( |
| 150 | personalSelfApplyRefusalReason( |
| 151 | eligible({ |
| 152 | status: 'proposed', |
| 153 | source: FLOW_PROPOSAL_SOURCE, |
| 154 | path: 'meta/flows/x.json', |
| 155 | external_ref: 'scooling.task:x', |
| 156 | }), |
| 157 | ), |
| 158 | 'SELF_APPLY_NOT_ADMITTED', |
| 159 | ); |
| 160 | }); |
| 161 | |
| 162 | it('empty author / mcp_access / project scope / other-assignee refuse', () => { |
| 163 | assert.equal( |
| 164 | personalSelfApplyRefusalReason(eligible(taskProposal(), { authorActorId: '' })), |
| 165 | 'SELF_APPLY_AUTHOR_UNVERIFIED', |
| 166 | ); |
| 167 | assert.equal( |
| 168 | personalSelfApplyRefusalReason(eligible(taskProposal(), { tokenType: 'mcp_access' })), |
| 169 | 'ROLE_NOT_ELIGIBLE', |
| 170 | ); |
| 171 | const project = taskProposal({ |
| 172 | bodyObj: { |
| 173 | proposal_kind: 'task_create', |
| 174 | task: { task_id: 't', kind: 'personal', scope: 'project', status: 'pending', title: 'P', workspace_id: 'ws' }, |
| 175 | }, |
| 176 | }); |
| 177 | assert.equal(personalSelfApplyRefusalReason(eligible(project)), 'SELF_APPLY_NOT_ADMITTED'); |
| 178 | const assignOther = taskProposal({ |
| 179 | bodyObj: { |
| 180 | proposal_kind: 'task_assign', |
| 181 | task_id: 't1', |
| 182 | scope: 'personal', |
| 183 | assignee_ref: OTHER, |
| 184 | }, |
| 185 | }); |
| 186 | assert.equal(isAdmittedSeamSelfApplyFingerprint(assignOther, ACTOR), false); |
| 187 | assert.equal(personalSelfApplyRefusalReason(eligible(assignOther)), 'SELF_APPLY_NOT_ADMITTED'); |
| 188 | const assignSelf = taskProposal({ |
| 189 | bodyObj: { |
| 190 | proposal_kind: 'task_assign', |
| 191 | task_id: 't1', |
| 192 | scope: 'personal', |
| 193 | assignee_ref: ACTOR, |
| 194 | }, |
| 195 | }); |
| 196 | assert.equal(personalSelfApplyRefusalReason(eligible(assignSelf)), null); |
| 197 | }); |
| 198 | |
| 199 | it('pending path slug is not admitted; rewritten path is', () => { |
| 200 | const pending = taskProposal({ path: 'meta/tasks/proposals/pending.json', proposal_id: 'prop-x' }); |
| 201 | assert.equal(matchesScoolingTaskFingerprint(pending), false); |
| 202 | assert.equal(matchesScoolingTaskFingerprint(pending, { allowPendingPath: true }), true); |
| 203 | }); |
| 204 | |
| 205 | it('external_ref helpers validate regex; malformed refuse', () => { |
| 206 | assert.equal(SCOOLING_TASK_EXTERNAL_REF_RE.test('scooling.task:ok'), true); |
| 207 | assert.equal(SCOOLING_MEDIA_EXTERNAL_REF_RE.test('scooling.media:ok'), true); |
| 208 | const bad = resolveOptionalScoolingExternalRef('scooling.review:x', SCOOLING_TASK_EXTERNAL_REF_RE); |
| 209 | assert.equal(bad.ok, false); |
| 210 | assert.equal(bad.status, 400); |
| 211 | assert.equal(readProposeExternalRefRaw({ body: { external_ref: 'scooling.task:a' } }), 'scooling.task:a'); |
| 212 | }); |
| 213 | }); |
| 214 | |
| 215 | describe('FINISH-COMPLETE-APPLY-KN-b integration — propose persist + approve class', () => { |
| 216 | const dataDir = path.join(tmpRoot, 'integ'); |
| 217 | beforeEach(() => { |
| 218 | fs.rmSync(tmpRoot, { recursive: true, force: true }); |
| 219 | fs.mkdirSync(dataDir, { recursive: true }); |
| 220 | process.env.TASK_WRITES_ENABLED = '1'; |
| 221 | }); |
| 222 | afterEach(() => { |
| 223 | delete process.env.TASK_WRITES_ENABLED; |
| 224 | }); |
| 225 | |
| 226 | it('persists external_ref on task propose; session-bound class holds after path rewrite', async () => { |
| 227 | const proposed = await handleTaskProposeRequest({ |
| 228 | dataDir, |
| 229 | vaultId: 'default', |
| 230 | userId: ACTOR, |
| 231 | role: 'editor', |
| 232 | proposalKind: 'task_create', |
| 233 | intent: 'create personal task', |
| 234 | sessionBound: true, |
| 235 | body: { |
| 236 | ...sampleTaskCreatePayload(), |
| 237 | task: { ...sampleTaskCreatePayload().task, task_id: 'task_fca_persist' }, |
| 238 | external_ref: 'scooling.task:persist-1', |
| 239 | }, |
| 240 | createProposal, |
| 241 | }); |
| 242 | assert.equal(proposed.ok, true); |
| 243 | const row = getProposal(dataDir, proposed.payload.proposal_id); |
| 244 | assert.equal(row.external_ref, 'scooling.task:persist-1'); |
| 245 | assert.match(row.path, /^meta\/tasks\/proposals\/.+\.json$/); |
| 246 | assert.notEqual(row.path, 'meta/tasks/proposals/pending.json'); |
| 247 | assert.equal( |
| 248 | personalSelfApplyRefusalReason( |
| 249 | eligible( |
| 250 | { |
| 251 | ...row, |
| 252 | task_meta: row.task_meta, |
| 253 | }, |
| 254 | { role: 'editor' }, |
| 255 | ), |
| 256 | ), |
| 257 | null, |
| 258 | ); |
| 259 | }); |
| 260 | |
| 261 | it('absent external_ref proposes ok but not admitted; malformed → 400', async () => { |
| 262 | const noRef = await handleTaskProposeRequest({ |
| 263 | dataDir, |
| 264 | vaultId: 'default', |
| 265 | userId: ACTOR, |
| 266 | role: 'editor', |
| 267 | proposalKind: 'task_create', |
| 268 | intent: 'create', |
| 269 | body: { ...sampleTaskCreatePayload(), task: { ...sampleTaskCreatePayload().task, task_id: 'task_fca_noref' } }, |
| 270 | createProposal, |
| 271 | }); |
| 272 | assert.equal(noRef.ok, true); |
| 273 | const row = getProposal(dataDir, noRef.payload.proposal_id); |
| 274 | assert.equal( |
| 275 | personalSelfApplyRefusalReason(eligible({ ...row, source: TASK_PROPOSAL_SOURCE })), |
| 276 | 'SELF_APPLY_NOT_ADMITTED', |
| 277 | ); |
| 278 | |
| 279 | const bad = await handleTaskProposeRequest({ |
| 280 | dataDir, |
| 281 | vaultId: 'default', |
| 282 | userId: ACTOR, |
| 283 | role: 'editor', |
| 284 | proposalKind: 'task_create', |
| 285 | intent: 'create', |
| 286 | body: { ...{ ...sampleTaskCreatePayload(), task: { ...sampleTaskCreatePayload().task, task_id: 'task_fca_badref' } }, external_ref: 'nope' }, |
| 287 | createProposal, |
| 288 | }); |
| 289 | assert.equal(bad.ok, false); |
| 290 | assert.equal(bad.status, 400); |
| 291 | assert.equal(bad.code, 'EXTERNAL_REF_INVALID'); |
| 292 | }); |
| 293 | |
| 294 | it('elevated task fingerprint does not self-apply', () => { |
| 295 | const elevated = taskProposal({ review_severity: 'elevated' }); |
| 296 | assert.equal(personalSelfApplyRefusalReason(eligible(elevated)), 'ELEVATED_OR_AUTO_FLAGGED'); |
| 297 | }); |
| 298 | |
| 299 | it('persists external_ref on media_external_link propose; class holds after path rewrite', async () => { |
| 300 | const fx = buildMediaWriteFixture(path.join(tmpRoot, 'media-integ')); |
| 301 | enableMediaExternalLinkWrites(fx.dataDir); |
| 302 | const consentId = grantActiveConsent(fx.dataDir, fx.vaultId, 'gdrive'); |
| 303 | const proposed = await handleMediaLinkProposeRequest({ |
| 304 | dataDir: fx.dataDir, |
| 305 | vaultId: fx.vaultId, |
| 306 | userId: ACTOR, |
| 307 | cliScopes: ['personal', 'project', 'org'], |
| 308 | intent: 'link personal media', |
| 309 | sessionBound: true, |
| 310 | body: { |
| 311 | ...sampleLinkProposeBody({ consent_id: consentId }), |
| 312 | external_ref: 'scooling.media:persist-1', |
| 313 | }, |
| 314 | createProposal, |
| 315 | }); |
| 316 | assert.equal(proposed.ok, true); |
| 317 | const row = getProposal(fx.dataDir, proposed.payload.proposal_id); |
| 318 | assert.equal(row.external_ref, 'scooling.media:persist-1'); |
| 319 | assert.match(row.path, /^meta\/media\/proposals\/.+\.json$/); |
| 320 | assert.notEqual(row.path, 'meta/media/proposals/pending.json'); |
| 321 | assert.equal( |
| 322 | personalSelfApplyRefusalReason( |
| 323 | eligible( |
| 324 | { |
| 325 | ...row, |
| 326 | media_meta: row.media_meta, |
| 327 | }, |
| 328 | { role: 'editor' }, |
| 329 | ), |
| 330 | ), |
| 331 | null, |
| 332 | ); |
| 333 | }); |
| 334 | }); |
| 335 | |
| 336 | describe('FINISH-COMPLETE-APPLY-KN-b e2e — personal task_create + media_external_link without Hub eval hop', () => { |
| 337 | const dataDir = path.join(tmpRoot, 'e2e'); |
| 338 | beforeEach(() => { |
| 339 | fs.rmSync(tmpRoot, { recursive: true, force: true }); |
| 340 | fs.mkdirSync(dataDir, { recursive: true }); |
| 341 | process.env.TASK_WRITES_ENABLED = '1'; |
| 342 | }); |
| 343 | afterEach(() => { |
| 344 | delete process.env.TASK_WRITES_ENABLED; |
| 345 | }); |
| 346 | |
| 347 | it('create+E1+class holds for session-bound personal task', async () => { |
| 348 | const proposed = await handleTaskProposeRequest({ |
| 349 | dataDir, |
| 350 | vaultId: 'default', |
| 351 | userId: ACTOR, |
| 352 | role: 'editor', |
| 353 | proposalKind: 'task_create', |
| 354 | intent: 'e2e', |
| 355 | sessionBound: true, |
| 356 | body: { |
| 357 | ...{ ...sampleTaskCreatePayload(), task: { ...sampleTaskCreatePayload().task, task_id: 'task_fca_e2e' } }, |
| 358 | external_ref: 'scooling.task:e2e-1', |
| 359 | }, |
| 360 | createProposal, |
| 361 | }); |
| 362 | assert.equal(proposed.ok, true); |
| 363 | const row = getProposal(dataDir, proposed.payload.proposal_id); |
| 364 | assert.equal(row.evaluation_status, 'passed'); |
| 365 | assert.equal(row.evaluated_by, ACTOR); |
| 366 | assert.equal(isPersonalSelfApplyClass(eligible(row, { role: 'editor' })), true); |
| 367 | }); |
| 368 | |
| 369 | it('create+E1+class holds for session-bound personal media_external_link', async () => { |
| 370 | const fx = buildMediaWriteFixture(path.join(tmpRoot, 'e2e-media')); |
| 371 | enableMediaExternalLinkWrites(fx.dataDir); |
| 372 | const consentId = grantActiveConsent(fx.dataDir, fx.vaultId, 'gdrive'); |
| 373 | const proposed = await handleMediaLinkProposeRequest({ |
| 374 | dataDir: fx.dataDir, |
| 375 | vaultId: fx.vaultId, |
| 376 | userId: ACTOR, |
| 377 | cliScopes: ['personal', 'project', 'org'], |
| 378 | intent: 'e2e media', |
| 379 | sessionBound: true, |
| 380 | body: { |
| 381 | ...sampleLinkProposeBody({ consent_id: consentId }), |
| 382 | external_ref: 'scooling.media:e2e-1', |
| 383 | }, |
| 384 | createProposal, |
| 385 | }); |
| 386 | assert.equal(proposed.ok, true); |
| 387 | const row = getProposal(fx.dataDir, proposed.payload.proposal_id); |
| 388 | assert.equal(row.evaluation_status, 'passed'); |
| 389 | assert.equal(row.evaluated_by, ACTOR); |
| 390 | assert.equal(isPersonalSelfApplyClass(eligible(row, { role: 'editor' })), true); |
| 391 | }); |
| 392 | }); |
| 393 | |
| 394 | describe('FINISH-COMPLETE-APPLY-KN-b stress — N cycles no cross-user leakage', () => { |
| 395 | it('distinct users never share admission', () => { |
| 396 | for (let i = 0; i < 100; i++) { |
| 397 | const a = taskProposal({ |
| 398 | proposal_id: `prop-a-${i}`, |
| 399 | external_ref: `scooling.task:a-${i}`, |
| 400 | }); |
| 401 | const b = taskProposal({ |
| 402 | proposal_id: `prop-b-${i}`, |
| 403 | external_ref: `scooling.task:b-${i}`, |
| 404 | }); |
| 405 | assert.equal(personalSelfApplyRefusalReason(eligible(a, { authorActorId: ACTOR, approverActorId: ACTOR })), null); |
| 406 | assert.equal( |
| 407 | personalSelfApplyRefusalReason(eligible(b, { authorActorId: ACTOR, approverActorId: OTHER })), |
| 408 | 'SELF_APPLY_AUTHOR_MISMATCH', |
| 409 | ); |
| 410 | } |
| 411 | }); |
| 412 | }); |
| 413 | |
| 414 | describe('FINISH-COMPLETE-APPLY-KN-b data-integrity — P2 strip + server evaluation', () => { |
| 415 | it('client evaluation_status stripped; E1 sets server audit', () => { |
| 416 | const stripped = stripClientEvaluationFields({ |
| 417 | evaluation_status: 'passed', |
| 418 | evaluated_by: 'forged', |
| 419 | evaluated_at: '2099-01-01T00:00:00.000Z', |
| 420 | path: 'meta/tasks/proposals/pending.json', |
| 421 | source: TASK_PROPOSAL_SOURCE, |
| 422 | external_ref: 'scooling.task:di-1', |
| 423 | body: JSON.stringify({ |
| 424 | proposal_kind: 'task_create', |
| 425 | task: { scope: 'personal', task_id: 't', kind: 'personal', status: 'pending', title: 'x', workspace_id: 'w' }, |
| 426 | }), |
| 427 | frontmatter: { [FM_PROPOSAL_SOURCE]: 'task', [FM_TASK_PROPOSAL_KIND]: 'task_create' }, |
| 428 | }); |
| 429 | assert.equal(stripped.evaluation_status, undefined); |
| 430 | const e1 = applyPersonalSelfApplyEvaluationE1(stripped, { |
| 431 | evaluatedBy: ACTOR, |
| 432 | sessionBound: true, |
| 433 | authorActorId: ACTOR, |
| 434 | evaluatedAt: '2026-07-27T00:00:00.000Z', |
| 435 | }); |
| 436 | assert.equal(e1.evaluation_status, 'passed'); |
| 437 | assert.equal(e1.evaluated_by, ACTOR); |
| 438 | assert.equal(e1.evaluated_at, '2026-07-27T00:00:00.000Z'); |
| 439 | }); |
| 440 | }); |
| 441 | |
| 442 | describe('FINISH-COMPLETE-APPLY-KN-b performance — E1 is pure and bounded', () => { |
| 443 | it('1000 E1 stamps stay under budget', () => { |
| 444 | const body = { |
| 445 | path: 'meta/tasks/proposals/pending.json', |
| 446 | source: TASK_PROPOSAL_SOURCE, |
| 447 | external_ref: 'scooling.task:perf', |
| 448 | body: JSON.stringify({ |
| 449 | proposal_kind: 'task_create', |
| 450 | task: { scope: 'personal', task_id: 't', kind: 'personal', status: 'pending', title: 'x', workspace_id: 'w' }, |
| 451 | }), |
| 452 | frontmatter: { [FM_PROPOSAL_SOURCE]: 'task', [FM_TASK_PROPOSAL_KIND]: 'task_create' }, |
| 453 | }; |
| 454 | const t0 = performance.now(); |
| 455 | for (let i = 0; i < 1000; i++) { |
| 456 | applyPersonalSelfApplyEvaluationE1(body, { |
| 457 | evaluatedBy: ACTOR, |
| 458 | sessionBound: true, |
| 459 | authorActorId: ACTOR, |
| 460 | }); |
| 461 | } |
| 462 | const ms = performance.now() - t0; |
| 463 | assert.ok(ms < 500, `E1 1000 cycles took ${ms}ms`); |
| 464 | }); |
| 465 | }); |
| 466 | |
| 467 | describe('FINISH-COMPLETE-APPLY-KN-b security — IDOR / credential / forge', () => { |
| 468 | it('IDOR: foreign partition never admits; shared/service/legacy_session cannot admit; forged evaluation ignored on E1 refuse', () => { |
| 469 | assert.equal( |
| 470 | personalSelfApplyRefusalReason(eligible(taskProposal(), { partitionOwned: false })), |
| 471 | 'NOT_PARTITION_OWNED', |
| 472 | ); |
| 473 | assert.equal( |
| 474 | personalSelfApplyRefusalReason(eligible(mediaProposal(), { partitionOwned: false })), |
| 475 | 'NOT_PARTITION_OWNED', |
| 476 | ); |
| 477 | assert.equal( |
| 478 | personalSelfApplyRefusalReason(eligible(taskProposal(), { sessionBound: false })), |
| 479 | 'SELF_APPLY_SESSION_BINDING_REQUIRED', |
| 480 | ); |
| 481 | assert.equal( |
| 482 | personalSelfApplyRefusalReason(eligible(taskProposal(), { authorActorId: ACTOR, approverActorId: OTHER })), |
| 483 | 'SELF_APPLY_AUTHOR_MISMATCH', |
| 484 | ); |
| 485 | assert.equal( |
| 486 | personalSelfApplyRefusalReason( |
| 487 | eligible({ status: 'proposed', source: DELEGATION_PROPOSAL_SOURCE }, { sessionBound: true }), |
| 488 | ), |
| 489 | 'SELF_APPLY_DELEGATION_REFUSED', |
| 490 | ); |
| 491 | const forged = applyPersonalSelfApplyEvaluationE1( |
| 492 | { |
| 493 | ...taskProposal({ path: 'meta/tasks/proposals/pending.json' }), |
| 494 | evaluation_status: 'passed', |
| 495 | evaluated_by: 'attacker', |
| 496 | }, |
| 497 | { sessionBound: false, evaluatedBy: ACTOR }, |
| 498 | ); |
| 499 | // sessionBound false → E1 does not stamp; forged fields remain on copy unless elevated clear |
| 500 | assert.notEqual(forged.evaluated_by, ACTOR); |
| 501 | }); |
| 502 | |
| 503 | it('notes tray still eligible; wrong-prefix task ref not admitted', () => { |
| 504 | const notes = { |
| 505 | status: 'proposed', |
| 506 | intent: SCOOLING_REVIEW_TRAY_INTENT, |
| 507 | external_ref: 'scooling.review:ok', |
| 508 | path: 'reviewed/ok.md', |
| 509 | }; |
| 510 | assert.equal(personalSelfApplyRefusalReason(eligible(notes)), null); |
| 511 | const wrongPrefix = taskProposal({ external_ref: 'scooling.review:nope' }); |
| 512 | assert.equal(personalSelfApplyRefusalReason(eligible(wrongPrefix)), 'SELF_APPLY_NOT_ADMITTED'); |
| 513 | }); |
| 514 | }); |
File History
1 commit
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6
docs: record AIP-b SD-21 land (KN #308)
Human
9 days ago