From de48008cca721a2dcb6b8dba8c0e738ace2673c0 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sun, 16 Jul 2017 14:32:38 +0300 Subject: Drop: duplicate yarn --- yarns.mdwn | 432 ------------------------------------------------------------- 1 file changed, 432 deletions(-) delete mode 100644 yarns.mdwn diff --git a/yarns.mdwn b/yarns.mdwn deleted file mode 100644 index 9deb11e..0000000 --- a/yarns.mdwn +++ /dev/null @@ -1,432 +0,0 @@ ---- -title: "A Gitano ruleset: tests" -author: Lars Wirzenius (liw@liw.fi) -date: 2017-02-05 -... - -Introduction -============================================================================= - -[Gitano][gitano] is the server software I use for my [personal git server][gitliwfi], -and also at [work][ql]. One of Gitano's primary features is a strong -language for defining access control, called [Lace][lace]. However, with -great power comes long shoelaces that get easily loosened. This -document explains what my ruleset does, and why. It is also a test -suite for the ruleset, to make sure it does what it's supposed to, but -avoids some of the more obvious pitfalls. - -[Gitano]: https://www.gitano.org.uk/ -[Lace]: https://www.gitano.org.uk/lace/ -[gitliwfi]: http://git.liw.fi/ -[ql]: http://qvarnlabs.com/ - -Discussion ------------------------------------------------------------------------------ - -* There's going to be repositories that are public to the world (in a - read-only manner) and those that are meant to be private within a - group of people (e.g., all of company staff, or just operations - staff). - -* Some people will have full write access to some repositories, - whereas everyone else (even those with Gitano accounts) have only - read access to those respositories. - -* When outsiders have write access, it may need to be restricted, such - that they can do things, but can't change master or other branches - themselves, or create release tags. We call these guests. - -* There's automated system, such as CI, which only ever need read-only - access. (If we find a need for a bot with write access later, we'll - re-think then. YAGNI.) - -Rough outline for ruleset ------------------------------------------------------------------------------ - -* Only a Gitano admin can create users, groups, and repositories, or - add users to groups. - -* All repository access is controlled via group membership. Each - repository is assumed to have three group associated with it: - `writers`, `readers`, and `guests`. These are per-repository - configuration variables, whose value should be the name of the - Gitano group that defines who are writers, readers, or guests, - correspondingly. - - For example, if `qvarn.git` has `writers` defined as - `qvarnlabs-staff`, then only those in the `qvarnlabs-staff` group - have full write access. - -* All groups have full read access. (Git doesn't really allow limiting - read at a more granular scale than a repository.) - -* Writers have full write access. They can push changes, and update - any branches and tags. - -* Guests are like writers, but can only update branches and tags - prefixed by their Gitano username. - -* Public repositories are marked by setting the configuration variable - `public` to `yes`. Anyone can clone public repositories, pull from - them, and cgit shows them to anyone. Public repositories are - published via the anonymous git prototocol. - - -The ruleset change to standard Gitano ruleset -============================================================================= - -The following lines added to `rules/project.lace` in the -`gitano-admin.git` repository implement the ruleset change, on top of -the standard Gitano ruleset. - - define repo_is_public config/public exact yes - allow "Everyone can read a public repo" op_read repo_is_public - - define user_is_repo_reader group exact ${config/readers} - allow "Readers may read" op_read user_is_repo_reader - - define user_is_repo_writer group exact ${config/writers} - allow "Writers may read and write" op_is_basic user_is_repo_writer - allow "Writers may update any branch" op_is_normal user_is_repo_writer - - define user_is_repo_guest group exact ${config/guests} - define ref_is_for_user ref prefix ${user}/ - allow "Guests may read and write" op_is_basic user_is_repo_guest - allow "Guests may update their own refs" op_is_normal user_is_repo_guest - - -Use cases as automated test scenarios -============================================================================= - -These [yarn][yarn] scenarios need to be run as a Gitano user who is in the -`gitano-admins` group so that they can create users, and do other -priviledged operations. Further, this should be done against a fresh -Gitano, without the test users etc. - -[yarn]: http://liw.fi/cmdtest/ - -Personas for use cases ------------------------------------------------------------------------------ - -* **Ian Inhouse Developer** is a staff member and works on a free software - project with the random silly name Qvarn. - -* **Olive Opshead** is a sysadmin and needs to maintain ops related - repositories, some of which are sensitive. - -* **Steven Sect** is the company secretary and needs to access some - private respositories with internal company data. - -* **Gabriella Guest** is an outside developer, collaborating on Qvarn - with Ian. Gabriella has been granted restricted commit access to the - Qvarn repository. - -* **CI** is an automated system that monitors some repositories to - build, test, and deliver software. - -Ian makes a bug fix in Qvarn ------------------------------------------------------------------------------ - - SCENARIO Ian can make a bug fix in Qvarn - WHEN admin creates user ian - AND admin creates group qvarndevs - AND admin adds ian to qvarndevs - AND admin creates repository qvarn - AND admin sets qvarn config writers to qvarndevs - THEN ian can clone qvarn - WHEN ian creates qvarn branch bugfix - AND ian changes qvarn branch bugfix - THEN ian can push qvarn - WHEN ian merges qvarn branch bugfix to master - THEN ian can push qvarn - FINALLY admin removes things that were created - -Steven can see Qvarn, but not push changes ------------------------------------------------------------------------------ - - SCENARIO Steven can clone Qvarn but not push changes - WHEN admin creates user steven - AND admin creates group qvarn-readers - AND admin adds steven to qvarn-readers - AND admin creates repository qvarn - AND admin sets qvarn config readers to qvarn-readers - AND admin sets qvarn config writers to qvarn-writers - THEN steven can clone qvarn - WHEN steven creates qvarn branch bugfix - AND steven changes qvarn branch bugfix - AND steven merges qvarn branch bugfix to master - THEN steven cannot push qvarn - FINALLY admin removes things that were created - -Ian can make a Qvarn release ------------------------------------------------------------------------------ - - SCENARIO Ian can make a Qvarn release - WHEN admin creates user ian - AND admin creates group qvarndevs - AND admin adds ian to qvarndevs - AND admin creates repository qvarn - AND admin sets qvarn config writers to qvarndevs - THEN ian can clone qvarn - WHEN ian creates qvarn branch bugfix - AND ian changes qvarn branch bugfix - THEN ian can push qvarn - WHEN ian merges qvarn branch bugfix to master - AND ian tags qvarn master branch with qvarn-1.0 - THEN ian can push qvarn with tags - FINALLY admin removes things that were created - -Steven can't push a release tag ------------------------------------------------------------------------------ - - SCENARIO Steven can't tag a Qvarn release - WHEN admin creates user steven - AND admin creates group qvarn-readers - AND admin creates group qvarn-writers - AND admin adds steven to qvarn-readers - AND admin creates repository qvarn - AND admin sets qvarn config readers to qvarn-readers - AND admin sets qvarn config writers to qvarn-writers - THEN steven can clone qvarn - WHEN steven tags qvarn master branch with qvarn-2.0 - THEN steven cannot push qvarn with tags - FINALLY admin removes things that were created - -Gabriella can push changes and tag with her own prefix ------------------------------------------------------------------------------ - - SCENARIO Gabriella can change and tag her own branch - WHEN admin creates user gabriella - AND admin creates group qvarn-guests - AND admin adds gabriella to qvarn-guests - AND admin creates repository qvarn - AND admin sets qvarn config guests to qvarn-guests - THEN gabriella can clone qvarn - WHEN gabriella creates qvarn branch gabriella/bugfix - AND gabriella changes qvarn branch gabriella/bugfix - THEN gabriella can push qvarn - WHEN gabriella tags qvarn gabriella/bugfix branch with gabriella/works - THEN gabriella can push qvarn with tags - FINALLY admin removes things that were created - -Steven can't read the ops/secrets repo ------------------------------------------------------------------------------ - - SCENARIO Steven can't clone ops/secrets - WHEN admin creates user steven - AND admin creates repository ops/secrets - THEN steven cannot clone ops/secrets - FINALLY admin removes things that were created - -A public repository can be clone with the anonymous git protocol ------------------------------------------------------------------------------ - - SCENARIO everyone can clone a public repository - WHEN admin creates repository qvarn - AND admin sets qvarn config public to yes - THEN we can clone qvarn via the git protocol - FINALLY admin removes things that were created - -Scenario step implementations -============================================================================= - -WHEN admin creates user ------------------------------------------------------------------------------ - - IMPLEMENTS WHEN admin creates user (\S+) - username = helper.get_next_match() - # FIXME: Create first, this is temporary - helper.append_to_list('users', username) - helper.gitano( - None, - 'user add {} {}@example.com Test {}'.format( - username, username, username)) - pubkey = helper.ssh_keygen(username) - helper.gitano(None, - 'as {} sshkey add default'.format(username), stdin=pubkey) - -WHEN admin creates group ------------------------------------------------------------------------------ - - IMPLEMENTS WHEN admin creates group (\S+) - group = helper.get_next_match() - # FIXME: Create first, this is temporary - helper.append_to_list('groups', group) - helper.gitano(None, 'group add {} Test group'.format(group)) - -WHEN admin adds user to group ------------------------------------------------------------------------------ - - IMPLEMENTS WHEN admin adds (\S+) to (\S+) - user = helper.get_next_match() - group = helper.get_next_match() - output = helper.gitano( - None, 'group adduser {} {}'.format(group, user)) - -WHEN admin created repository ------------------------------------------------------------------------------ - - IMPLEMENTS WHEN admin creates repository (\S+) - repo = helper.get_next_match() - # FIXME: Create first, this is temporary - helper.append_to_list('repositories', repo) - helper.gitano(None, 'create {}'.format(repo)) - - # Make a commit in master in the repo, push that. - user = 'admin' - url = helper.repo_ssh_url(repo) - dirname = helper.local_checkout_dirname(user, repo) - helper.git_as_checked(None, ['clone', url, dirname]) - cliapp.runcmd(['git', 'config', 'user.email', user], cwd=dirname) - cliapp.runcmd(['git', 'config', 'user.name', user], cwd=dirname) - with open(os.path.join(dirname, 'foo.txt'), 'a') as f: - f.write('') - cliapp.runcmd(['git', 'add', 'foo.txt'], cwd=dirname) - cliapp.runcmd(['git', 'commit', '-mfoo'], cwd=dirname) - helper.git_as_checked(None, ['push', '--all'], cwd=dirname) - -WHEN admin sets repository config ------------------------------------------------------------------------------ - - IMPLEMENTS WHEN admin sets (\S+) config (\S+) to (\S+) - repo = helper.get_next_match() - key = helper.get_next_match() - value = helper.get_next_match() - helper.gitano(None, 'config {} set {} {}'.format(repo, key, value)) - -THEN a user can clone a repository ------------------------------------------------------------------------------ - - IMPLEMENTS THEN (\S+) can clone (\S+) - user = helper.get_next_match() - repo = helper.get_next_match() - url = helper.repo_ssh_url(repo) - dirname = helper.local_checkout_dirname(user, repo) - helper.git_as_checked(user, ['clone', url, dirname]) - cliapp.runcmd(['git', 'config', 'user.email', user], cwd=dirname) - cliapp.runcmd(['git', 'config', 'user.name', user], cwd=dirname) - -THEN a user can't clone a repository ------------------------------------------------------------------------------ - - IMPLEMENTS THEN (\S+) cannot clone (\S+) - user = helper.get_next_match() - repo = helper.get_next_match() - url = helper.repo_ssh_url(repo) - dirname = helper.local_checkout_dirname(user, repo) - exit, out, err = helper.git_as(user, ['clone', url, dirname]) - helper.assertNotEqual(exit, 0) - -THEN a repository can be cloned over the git protocol ------------------------------------------------------------------------------ - - IMPLEMENTS THEN we can clone (\S+) via the git protocol - repo = helper.get_next_match() - server = os.environ['GITANO_SERVER'] - url = 'git://{}/{}'.format(server, repo) - dirname = helper.local_checkout_dirname('anonymous', repo) - cliapp.runcmd(['git', 'clone', url, dirname]) - -WHEN a user creates a local branch ------------------------------------------------------------------------------ - - IMPLEMENTS WHEN (\S+) creates (\S+) branch (\S+) - user = helper.get_next_match() - repo = helper.get_next_match() - branch = helper.get_next_match() - dirname = helper.local_checkout_dirname(user, repo) - cliapp.runcmd(['git', 'checkout', '-b', branch], cwd=dirname) - -WHEN a user changes a branch locally ------------------------------------------------------------------------------ - - IMPLEMENTS WHEN (\S+) changes (\S+) branch (\S+) - user = helper.get_next_match() - repo = helper.get_next_match() - branch = helper.get_next_match() - dirname = helper.local_checkout_dirname(user, repo) - with open(os.path.join(dirname, 'foo.txt'), 'a') as f: - f.write('foo\n') - cliapp.runcmd(['git', 'add', 'foo.txt'], cwd=dirname) - cliapp.runcmd(['git', 'commit', '-mfoo'], cwd=dirname) - -THEN a user can push all local branches ------------------------------------------------------------------------------ - - IMPLEMENTS THEN (\S+) can push (\S+) - user = helper.get_next_match() - repo = helper.get_next_match() - url = helper.repo_ssh_url(repo) - dirname = helper.local_checkout_dirname(user, repo) - helper.git_as_checked(user, ['push', '--all', 'origin'], cwd=dirname) - -THEN a user can push all local tags ------------------------------------------------------------------------------ - - IMPLEMENTS THEN (\S+) can push (\S+) with tags - user = helper.get_next_match() - repo = helper.get_next_match() - url = helper.repo_ssh_url(repo) - dirname = helper.local_checkout_dirname(user, repo) - helper.git_as_checked(user, ['push', '--tags', 'origin'], cwd=dirname) - -THEN a user can't push local branches ------------------------------------------------------------------------------ - - IMPLEMENTS THEN (\S+) cannot push (\S+) - user = helper.get_next_match() - repo = helper.get_next_match() - dirname = helper.local_checkout_dirname(user, repo) - exit, out, err = helper.git_as( - user, - ['push', '--all', 'origin'], cwd=dirname) - sys.stdout.write(out) - sys.stderr.write(err) - helper.assertNotEqual(exit, 0) - -THEN a user can't push local tags ------------------------------------------------------------------------------ - - IMPLEMENTS THEN (\S+) cannot push (\S+) with tags - user = helper.get_next_match() - repo = helper.get_next_match() - dirname = helper.local_checkout_dirname(user, repo) - exit, out, err = helper.git_as( - user, - ['push', '--tags', 'origin'], cwd=dirname) - helper.assertNotEqual(exit, 0) - -WHEN a user merges a branch locally ------------------------------------------------------------------------------ - - IMPLEMENTS WHEN (\S+) merges (\S+) branch (\S+) to (\S+) - user = helper.get_next_match() - repo = helper.get_next_match() - branch_from = helper.get_next_match() - branch_to = helper.get_next_match() - dirname = helper.local_checkout_dirname(user, repo) - cliapp.runcmd(['git', 'checkout', branch_to], cwd=dirname) - cliapp.runcmd(['git', 'merge', branch_from], cwd=dirname) - -WHEN a user creates a local tag ------------------------------------------------------------------------------ - - IMPLEMENTS WHEN (\S+) tags (\S+) (\S+) branch with (\S+) - user = helper.get_next_match() - repo = helper.get_next_match() - branch = helper.get_next_match() - tag = helper.get_next_match() - dirname = helper.local_checkout_dirname(user, repo) - cliapp.runcmd(['git', 'tag', '-mrelease!', tag], cwd=dirname) - -FINALLY clean up anything created during tests ------------------------------------------------------------------------------ - - IMPLEMENTS FINALLY admin removes things that were created - def iter(var, prefix): - items = helper.get_variable(var, []) - for item in items: - helper.gitano_confirm_with_token(prefix, item) - iter('users', 'user del') - iter('groups', 'group del') - iter('repositories', 'destroy') -- cgit v1.2.1