Add policy-bound credential submission and native DLP audit proofs
This commit is contained in:
1 parent
b991ee9da6
commit
c8b6ff9cdd
45 files changed
+777
-98
No files matched your search
@@ -17,7 +17,7 @@ test('agent vault inventory is scoped, classified and contains opaque references
|
||||
assert.deepEqual(await a.fill({credentialRef:rows[0].credentialRef}),{completed:true});assert.equal(f.scripts,1);
|
||||
await assert.rejects(a.fill({credentialRef:rows[0].credentialRef}));assert.equal(f.scripts,1);
|
||||
assert.doesNotMatch(JSON.stringify(f.events),/private|password|credentialRef/);
|
||||
assert.deepEqual(Object.keys(a).sort(),['clear','fill','list','status']);
|
||||
assert.deepEqual(Object.keys(a).sort(),['clear','fill','list','prepare','status']);
|
||||
});
|
||||
test('locked vault and failed/incomplete classifier cannot export inventory',async()=>{
|
||||
for(const mode of ['locked','block','incomplete','error','changed']){const f=fixture();if(mode==='locked')f.lock();else f.cb.inspect=async()=>{if(mode==='error')throw Error('private-password');if(mode==='changed')f.rows[0].origin='https://changed.example';return {decision:mode==='block'?'block':'allow',coverage:{complete:mode!=='incomplete'}};};await assert.rejects(f.make().list());}
|
||||
@@ -50,3 +50,8 @@ test('direct vault arguments reject secret-bearing or arbitrary extra fields',as
|
||||
test('allow verdict with unavailable inspection marker cannot export references',async()=>{
|
||||
for(const ruleId of ['uninspectable','size-limit','inspection-incomplete','unavailable','timeout']){const f=fixture();f.cb.inspect=async()=>({decision:'allow',ruleId});await assert.rejects(f.make().list());}
|
||||
});
|
||||
test('prepare submission has a separate default-off scope and regular fill never arms',async()=>{const f=fixture();let arms=0;f.cb.prepareSubmission=async()=>{arms++;return {prepared:true};};const a=f.make(),[row]=await a.list();await assert.rejects(a.prepare({credentialRef:row.credentialRef}));assert.equal(f.scripts,0);assert.deepEqual(await a.fill({credentialRef:row.credentialRef}),{completed:true});assert.equal(arms,0);});
|
||||
test('controlled prepare arms only once after native fill and returns sanitized status',async()=>{const f=fixture();f.c.policy.agents.scopes.push('vault:prepare-submit');f.c.policy.passwordManager.controlledSubmission={enabled:true,forms:[{id:'login',actionUrl:'https://work.example/session',usernameField:'user',passwordField:'pass'}]};let armed=0,credential,after=0;f.c.webContents.executeJavaScriptInIsolatedWorld=async()=>({completed:true,formId:'login'});f.cb.prepareSubmission=async value=>{armed++;credential=value.credential;assert.equal(value.formId,'login');assert.equal(value.credential.password,'private-password');return {prepared:true,password:'must-not-export',formId:'private'};};f.cb.afterFill=()=>after++;const a=f.make(),[row]=await a.list();assert.deepEqual(await a.prepare({credentialRef:row.credentialRef}),{completed:true,prepared:true});assert.equal(armed,1);assert.equal(after,1);assert.equal(credential.password,'');assert.equal(credential.username,'');await assert.rejects(a.prepare({credentialRef:row.credentialRef}));assert.equal(armed,1);assert.doesNotMatch(JSON.stringify(f.events),/private-password|credentialRef/);});
|
||||
test('revocation or failed trusted handoff stops native credential write and consumes reference',async()=>{for(const mode of ['revoked','error','aborted']){const f=fixture(),controller=new AbortController();f.cb.beforeFill=async()=>{if(mode==='revoked')f.invalidate();if(mode==='error')throw Error('private handoff error');if(mode==='aborted')controller.abort();};const a=f.make(),[row]=await a.list();await assert.rejects(a.fill({credentialRef:row.credentialRef},{signal:controller.signal}),{message:'Managed vault operation refused'});assert.equal(f.scripts,0);await assert.rejects(a.fill({credentialRef:row.credentialRef}));}});
|
||||
test('controlled policy disabled and native renderer form mismatch never arm broker',async()=>{for(const mode of ['disabled','native-fail']){const f=fixture();f.c.policy.agents.scopes.push('vault:prepare-submit');f.c.policy.passwordManager.controlledSubmission={enabled:mode!=='disabled',forms:[{id:'login',actionUrl:'https://work.example/session',usernameField:'user',passwordField:'pass'}]};let armed=0;f.cb.prepareSubmission=async()=>{armed++;return {prepared:true};};f.c.webContents.executeJavaScriptInIsolatedWorld=async()=>{throw Error('Form changed');};const a=f.make(),[row]=await a.list();await assert.rejects(a.prepare({credentialRef:row.credentialRef}));assert.equal(armed,0);}});
|
||||
test('post-arm revocation and handoff completion failure cancel only the returned private lease',async()=>{for(const mode of ['revoked','after-fill-error']){const f=fixture();f.c.policy.agents.scopes.push('vault:prepare-submit');f.c.policy.passwordManager.controlledSubmission={enabled:true,forms:[{id:'login',actionUrl:'https://work.example/session',usernameField:'user',passwordField:'pass'}]};let cancelled=0,armed=0;f.c.webContents.executeJavaScriptInIsolatedWorld=async()=>({completed:true,formId:'login'});f.cb.prepareSubmission=async()=>{armed++;if(mode==='revoked')f.invalidate();return {prepared:true,cancel:()=>cancelled++};};if(mode==='after-fill-error')f.cb.afterFill=()=>{throw Error('Private UI error');};const a=f.make(),[row]=await a.list();await assert.rejects(a.prepare({credentialRef:row.credentialRef}),{message:'Managed vault operation refused'});assert.equal(armed,1);assert.equal(cancelled,1);await assert.rejects(a.prepare({credentialRef:row.credentialRef}));assert.equal(armed,1);}});
|
||||
Reference in new issue
Block a user