read some immutable EVM property that contracts expose
Hmmm ... not sure what you read. There is certainly immutable blockchain info about the account that signed the transaction (or the contract) that deployed the contract but I think that is like events and not accessible from Solidity. Possibly someone else will chime in with a method.
A practical solution to your problem lies in this requirement:
of contracts which we ourselves wrote
That simplifies matters because you only need to keep track of what you do.
For example, in a hub and spoke pattern with a contract factory acting as the hub, it can keep track of deployed contracts. Supposed the hub has:
mapping(address => bool) public isTrusted;
Then it only needs to implement access control to limit access to "trusted" contracts:
modifier onlyTrusted {
require(isTrusted[msg.sender], "I don't know you.");
_;
Possibly the Hub isn't the only contract concerned with access control because the topology is more intricate. Still, you just need each interested contract to know the source of authority and ask:
modifier onlyTrusted {
require(whiteListContract.isTrusted(msg.sender), "It doesn't know you.");
_;
}
There are a few standardized contracts that implement this sort of thing. I'd suggest checking out Open Zeppelin "Whitelist" and "AccessControl." They each have methods to add and remove addresses from the list of things that are trusted. The maintenance of the lists is itself a function that deserves access control of its own (onlyOwner?) but it can work in a decentralized context, e.g. only trust contracts that this factory made itself:
function deployNewContract() public returns(address) { // anyone can
MyThing t = new MyThing();
// now add address(t) to the whitelist, depending on which implementation you choose
return address(t);
}
You know t is a certain kind of contract with no unexpected behaviour because of where it came from.
Hope it helps.