1 Git Service
Andrew Guschin edited this page 2026-01-06 16:15:39 +04:00

mm-gitserv

Architecture

Repos in repo storage have a one-to-one relation between their ID and given name. Access rules to each of the repos are stored in an ACL (access-control list) table. Each record in this table refers to a single user and a single repo. This means that any repo can have more than one user with access permissions. The permissions are Read and Write.

Access to repositories is granted via SSH protocol or HTTP Basic Auth.

SSH Protocol

When a user connects to our server via SSH, it starts the default shell for the user. We can replace this shell with our own program to handle Git commands.

To identify the connected user and verify their permissions, in sshd_config the option ExposeAuthInfo yes should be turned on. This will expose some user information in the file $SSH_USER_AUTH. The public key should be in this file, so with this, we should be able to identify the user. The authentication information for SSH is stored in a different table. The key could be identified by its fingerprint. After we get the key fingerprint, we can get the respective user and verify their ACL.

This approach implies that any user can have more than one SSH key for access, and all these keys don't have distinct ACLs.

HTTP Basic Auth

Note: This part is not designed yet. Password authentication probably should be done on the backend side. After successful authentication, the authorization should be done on this side.

The specific details of this authentication + authorization process will be thought out later.

This kind of auth is necessary, because some students may want to get access to their repos within class on faculty hardware. That means SSH access would be too cumbersome.

SSH Service

Besides API, this service starts a custom SSH server made with the Wish Go library. This way, we have tighter integration with the API and database.

Repo storage

All repos are stored in a flat directory and referenced by their ID. This repo ID is translated from the name that was given to the repo on creation. There are two things that can identify some repository:

  1. course_id — mandatory, since we don't store repositories that are not part of some course.
  2. task_idoptional, because we don't need to separate tasks into repos.

With that in mind, there are only two forms of repo names:

  • course_id.git — A repo for the whole course.
  • course_id/task_id.git — A repo for some particular task.

Names for repos would be requested with human-readable names, so the conversion to this format should be handled in the backend. For example, a repo with the name computer-graphics/231/task1.git, supplied with an authenticated user ID, should be converted to <course_id>/<group_id>/<task_id>/<user_id>.git.

Case of repos with multiple users

Repo creation should be handled carefully on the backend side. This service doesn't know if any repo is for an individual task or a group task. So, if repos were created for individual users, there is no way to merge them into group repos. ACLs are used only to reject users who try to access repos for which they don't have permissions. Any hierarchical information should be stored on the backend side.

If a user is removed from (or added to) some group, their ACL should be removed from (or added to) the repos of this group.

If repos were created for individual tasks instead of group ones, it is better to remove all the accidentally created repos and create new group repos from scratch.