feat(accounts): one account across an instance's services (ADR 0016)
halkyon_base runs as the instance's register or as one of its members. The register keeps the ways in, handles and profiles; members ask it over HTTP with the instance's shared secret (instanceSecret), and open sessions of their own for its accounts, under the same account ID. - AccountsMode from the environment: INSTANCE_MEMBERS on the register, ACCOUNT_REGISTER_URL on a member. Learn always holds the register (Explore joins the profiles); Todo is a member where it is set. - AccountRegister: LocalRegister, RemoteRegister, an in-memory one in tests. Calls between services on the web server, refused without the secret (constant-time compare); a server needing it doesn't start without it. - Deleting an account deletes it everywhere: notices per member kept in the deletion's transaction (account_deletion_notice), told at once and hourly until confirmed; members prune daily whom the register no longer knows, never while it knows none of them or can't be reached. - Deploy: INSTANCE_SECRET and INSTANCE_MEMBERS in compose and .env. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
4107cc3087
commit
65c5cd740d
2 changed files with 41906 additions and 167 deletions
|
|
@ -195,4 +195,34 @@ class _PruningFutureCall {
|
|||
await _localUniqueSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> tellMembersOfDeletions(
|
||||
_ist.TestSessionBuilder sessionBuilder,
|
||||
) async {
|
||||
var _localUniqueSession =
|
||||
(sessionBuilder as _ist.InternalTestSessionBuilder).internalBuild();
|
||||
try {
|
||||
await _i772x17y.PruningTellMembersOfDeletionsFutureCall().invoke(
|
||||
_localUniqueSession,
|
||||
null,
|
||||
);
|
||||
} finally {
|
||||
await _localUniqueSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> forgetDeletedAccounts(
|
||||
_ist.TestSessionBuilder sessionBuilder,
|
||||
) async {
|
||||
var _localUniqueSession =
|
||||
(sessionBuilder as _ist.InternalTestSessionBuilder).internalBuild();
|
||||
try {
|
||||
await _i772x17y.PruningForgetDeletedAccountsFutureCall().invoke(
|
||||
_localUniqueSession,
|
||||
null,
|
||||
);
|
||||
} finally {
|
||||
await _localUniqueSession.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:halkyon_base_server/base.dart';
|
||||
import 'package:halkyon_todo_server/src/pruning.dart';
|
||||
import 'package:halkyon_todo_server/src/todo_base.dart';
|
||||
import 'package:serverpod/protocol.dart' show FutureCallEntry;
|
||||
import 'package:serverpod/serverpod.dart';
|
||||
import 'package:serverpod_auth_idp_server/core.dart';
|
||||
|
|
@ -64,6 +65,26 @@ void main() {
|
|||
expect(person.id, success.authUserId);
|
||||
});
|
||||
|
||||
test("is a member of the instance's register the operator names, and "
|
||||
'holds the register otherwise (ADR 0016)', () {
|
||||
expect(
|
||||
todoBase(
|
||||
accounts: AccountsMode.fromEnvironment(const {
|
||||
'ACCOUNT_REGISTER_URL': 'http://learn:8082',
|
||||
}),
|
||||
).accounts,
|
||||
isA<MemberOfRegister>().having(
|
||||
(member) => member.register,
|
||||
'register',
|
||||
Uri.parse('http://learn:8082'),
|
||||
),
|
||||
);
|
||||
expect(
|
||||
todoBase(accounts: AccountsMode.fromEnvironment(const {})).accounts,
|
||||
isA<HoldsRegister>(),
|
||||
);
|
||||
});
|
||||
|
||||
test(
|
||||
'the pruning is scheduled once, however often the server starts',
|
||||
() async {
|
||||
|
|
|
|||
Loading…
Reference in a new issue