You don't really need all that much CI-specific stuff for most of that, except maybe the secrets, although you will end up duplicating some CI features if you choose not to use them, but that's usually not too hard.
Long time ago I implemented my own "CI" system. The basic idea was that by putting a make wrapper in the MAKE env variable I would intercept recursive makefile executions and I would spawn tasks in a message queue. Workers would pick up the messages and perform a fast checkout from a hot git repo cache in each node (using git --references). It worked as a charm. The exact same makefiles would work also locally out of the box