Has anyone tried using the new user-level access DML operations with the automated process user, say in a platform event trigger?
It seems as though calling Database.insert(records, AccessLevel.USER_MODE)
results in an exception be thrown on insert because the user seemingly has no access to any fields on the object - I'd expect it to have access to everything still.
I've done some basic experiements in a brand new scratch org and it seems like it does lose access to fields, which for ISVs is not great if every query/DML operation needs to check which user is running the code prior to using these new features.
The Experiment
Setup
I created a platform event, called ObjRequest__e
and added a custom 255 text field called ObjName__c
.
I also created a custom object called Obj__c
, that has a standard Text name field, and one custom Datetime field called Stamp__c
, with FLS completely cleared out so no user has access to it.
I created a simple trigger for the platform event that will run as the Automated Process user:
trigger ObjRequest_AfterInsert on ObjRequest__e (after insert) {
for(ObjRequest__e event : Trigger.New) {
if(String.isNotBlank(event.ObjName__c)) {
Objs.insertRecord(event.ObjName__c);
}
}
}
... and a class with a single static method that inserts Obj__c
records with the name given, automatically setting the Stamp__c
field:
public with sharing class Objs {
public static void insertRecord(String name) {
Obj__c o = new Obj__c(name = name, Stamp__c = Datetime.now());
try {
Database.insert(o, AccessLevel.USER_MODE);
} catch (DMLException e) {
System.debug(e.getMessage());
for(Integer i = 0; i < e.getNumDml(); i++) {
System.debug(e.getDmlFieldNames(i));
}
}
}
}
Test
To test functionality as each user I ran this code via execute anonymous:
Objs.insertRecord('test' + Datetime.now().time());
EventBus.publish(new List<ObjRequest__e>{new ObjRequest__e(ObjName__c = 'test' + Datetime.now().time())});
The logs for the running user contained this, which is to be expected:
07:04:07.189 (220462445)|USER_DEBUG|[9]|DEBUG|Operation failed due to fields being inaccessible on Sobject Obj__c, check errors on Exception or Result!
07:04:07.189 (220654470)|USER_DEBUG|[11]|DEBUG|(Stamp__c)
The logs for the Automated Process user contain the same thing:
07:04:08.1 (26859159)|USER_DEBUG|[9]|DEBUG|Operation failed due to fields being inaccessible on Sobject Obj__c, check errors on Exception or Result!
07:04:08.1 (27091582)|USER_DEBUG|[11]|DEBUG|(Stamp__c)
So it appears as though enforcing user mode on DML strips the Automated Process user of it's system-level access, which is a bit of a downer from the POV of trying to simplify code if we now need special handling for code that might get run by that user.
As a final quick test I updated FLS to grant write access on Stamp__c
to all profiles. Now when running the same exec anon snippet, the record for the running user is created no problem, but the Automated Process user fails to insert with the same exception as before.
Are my tests valid? Is this how this feature should work?