WheelmachineDocs
Open app

Give each team the repositories on GitHub and GitLab its machines may read, and those they may push to. No token ever goes into a machine: a fetch works only for a repository the team may read, and a push only for one it may write - as the person who holds the machine, and never to a protected branch.

Connected code hosts, and a team given a repository
wm code
wm code repos code_01j9z3...
wm code grant prj_01j9z3... code_01j9z3... acme/api write

Connect GitHub#

An organisation's owners and admins - or you, in your own account - install Wheelmachine's GitHub App on Code, Connect GitHub, and choose its repositories. Finish in a browser signed in to Wheelmachine as you (wm code connect github prints the same link). Add or remove repositories on GitHub at any time: a repository taken from the App is taken from every team given it.

Connect GitLab#

An organisation's owners and admins - or you, in your own account - connect gitlab.com in one approval: on the dashboard's Code page, Connect GitLab. GitLab asks you to sign in and to let Wheelmachine in; approve it and you are back on the Code page with GitLab connected - no token to make, copy or paste. Finish in the browser you started from, signed in to Wheelmachine as you. Its repositories are the GitLab projects you are a Developer, Maintainer or Owner of.

Disconnect it, and Wheelmachine revokes its access on GitLab too. Revoke it yourself on GitLab instead (your profile's Applications), and its repositories stop reaching the teams' machines; connect GitLab again with the same GitLab account, and the teams have back what they were given.

Your company's own GitLab#

For a GitLab your company runs itself, make a group access token in the group's Settings › Access tokens, with the role Developer and the scopes read_repository and write_repository, and add it on the Code page (Use your company's own GitLab server), with wm code connect gitlab or with POST /v1/code/gitlab. It is stored encrypted and never shown again; disconnect it to take it away.

Give a team repositories#

A team's full managers, the organisation's owners and admins - or you, in your own account - give it repositories of a connection, each to read (clone and fetch) or to write (push too). Everyone in the team sees what it was given. A machine reaches its team's repositories:

Take a repository away, or a person out of the team, and the team's machines lose it at once. A machine handed off reaches what its new holder's team was given, and pushes as its new holder.

A machine's pushes carry the name of the person who holds it, so each person links their own GitHub and GitLab once: Code, Your accounts. A machine can clone and fetch without a link; a push without one is refused and says so.

Your link stays fresh by itself. Its tokens are stored encrypted, never in a machine. Unlink stops your machines' pushes there and revokes the link on GitHub or GitLab too. If you take the approval back on GitHub or GitLab yourself, your machines' pushes there stop, and the Code page offers Link again the next time Wheelmachine renews the link. On a GitLab connected by a group's token - your company's own - nobody's account is linked: pushes there go with the group's token.

Protected branches and push rules#

No machine pushes to a protected branch: changes reach it through a pull request on GitHub, or a merge request on GitLab. An organisation's owners and admins - or you, in your own account - choose the protected branches under Protected branches on the Code page, or with PUT /v1/code/protected and a cloud:* key of the whole account. Until they do, main, master and release/** are protected; they may protect none.

A team's full managers, and the owners and admins, can limit a team's pushes to some branches: Push rules on its row, Only these branches, such as feature/** or fix/*, and its tags or not. A team's rule narrows the protected branches, never widens them: a protected branch stays out whatever the team's rule says. Without a rule, "Read and push" is any branch but the protected ones, and any tag.

Patterns are GitHub's: * is any part of a name but /, ** any part with / too, and ? one character. release/** holds release/1.0 and release/eu/2; qa/* holds qa/one but not qa/one/two. A push naming a protected branch answers "main is protected: changes reach it through a pull request" (a merge request, on GitLab); one outside the team's rule, "this team's machines may push only to feature/** or fix/*".

In a machine#

Clone, fetch and push as always, with the repository's https address:

shell
git clone https://github.com/acme/api.git
git push

Git in a machine reaches your team's repositories with no token in the machine. A fetch uses the team's access. A push uses the holder's own linked account, and only to the branches the account and the team allow. For your company's own GitLab, run this once in the machine:

shell
git config --global url."http://169.254.169.251:7703/gitlab.example.com/".insteadOf https://gitlab.example.com/

Everything else works as it did: public repositories, ones the team was not given (with your own sign-in), Git LFS, and git@github.com: addresses with your own SSH key. A push to a repository the team was given only to read answers 403, with words saying why. With its internet closed, or a list that does not name the host, a machine reaches its team's repositories and nothing else of GitHub or GitLab: no public repository, none the team was not given, no Git LFS. A closed machine can still push to its team's repositories, and a push can start that repository's own CI, which runs outside the machine with its own internet.

On GitLab, a push to a repository your team was given takes only the options that open a merge request: merge_request.create, merge_request.target, merge_request.title, merge_request.description, merge_request.draft and merge_request.remove_source_branch. Any other option is refused, and says so, so no option can merge or name another project. [skip ci] in a commit message or a merge request's title still skips a pipeline. A description with a line beginning with /, with spaces before it or not, is refused too, as GitLab would run it as a command: write \/ to show one.

Pull requests#

A machine can open a pull request as the last step of its work. People merge it: this does not merge, approve or close anything.

What a machine reaches, and a pull request from it
wm machines repos box
wm machines pull-request box acme/api --head agent/sign-in --base main --title "Sign in works again"

An agent has the same as list_repositories and open_pull_request. A key that runs commands (cloud:machines:exec) opens one; only the person who holds the machine may ask.

A pull request needs what a push needs: a repository the team may push to, the holder's own account linked (a GitLab connected by a group's token needs no link), and a machine whose internet reaches the host. Its head is a branch of the same repository that the team's machines may push to, so not a fork and not a protected branch. Its base may be a protected branch.

On GitHub#

It opens at once under the holder's own account, and answers its number and address. For one person and repository, at most 5 open a minute and about 60 an hour, with up to about 120 in a first hour; for one person, 10 a minute; for an account, 20 a minute. What GitHub refuses uses up none of those, but for one person at most 30 a minute are asked of GitHub at all, refused or not.

Pull requests need a permission Wheelmachine's GitHub App did not ask for at first. GitHub asks an owner of each account that installed the App to accept it, by e-mail and on the App's page in that account's settings. Until then, a pull request is refused with words saying so, and where to accept it.

On GitLab#

A merge request opens with a push, so nothing is open yet: the answer is a line of git to run in your clone, in the machine.

shell
git push -o merge_request.create -o merge_request.target=main -o 'merge_request.title=Sign in works again' origin agent/sign-in

GitLab opens it, or updates the one open from that branch, and git prints its address. It goes under the holder's linked account, or on your company's own GitLab under its group's token. The push has to send new commits: if git says everything is up to date, make a commit first.

Line breaks in the description go as \n, so a \n written in the body becomes a line break too. A body with a line beginning with /, with spaces before it or not, is refused, as GitLab would run that line as a command: write \/ to show one. So is a title, body or branch holding U+FFFD, the character that stands for unreadable text, as a machine's push may not carry it.