summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2017-03-05 15:48:39 +0200
committerLars Wirzenius <liw@liw.fi>2017-03-05 15:48:39 +0200
commit836f5bdd368bf836ba391e82690e330199307497 (patch)
treed333322b29952e1a09e6941c0449a04f2735dc6d
parent91aa7443eb1b761de1c3a0b9d09f2dbed4256d57 (diff)
downloadgit.liw.fi-ruleset-tests-836f5bdd368bf836ba391e82690e330199307497.tar.gz
Tweak wording, formatting
-rw-r--r--000.yarn302
1 files changed, 140 insertions, 162 deletions
diff --git a/000.yarn b/000.yarn
index cd2057d..a06185f 100644
--- a/000.yarn
+++ b/000.yarn
@@ -7,9 +7,9 @@ date: 2017-02-04
Introduction
=============================================================================
-[Gitano][] is the server software I use for my personal git server,
-and also at [work][]. One of Gitano's primary features is a strong
-language for defining access control, called [Lace][]. However, with
+[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
@@ -17,189 +17,92 @@ avoids some of the more obvious pitfalls.
[Gitano]: https://www.gitano.org.uk/
[Lace]: https://www.gitano.org.uk/lace/
-[work]: http://qvarnlabs.com/
-
-
-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.
-
-* **Tina Thirdparty** is an outside developer working on Qvarn as a
- full member, and needs full write access to the repository.
-
-* **J. R. Hacker** is an outsider who contributes to the projects, but
- has no need to commit to any the repositories. Instead, they
- maintain their own repository elsewhere, and Ian or Tina access that.
-
-* **CI** is an automated system that monitors some repositories to
- build, test, and deliver software.
-
-
-Use cases
------------------------------------------------------------------------------
-
-* Ian fixes a bug in Qvarn. (Or adds a feature: same process.)
-
- * Ian clones Qvarn to his laptop, or updates his existing clone.
- * Ian creates a branch in the local clone and makes changes.
- * Ian pushes the branch to the git server.
- * After others have reviewed his changes, Ian merges them to
- master, and pushes master to the git server.
- * CI notices the change, runs tests, and builds and publishes a CI
- build of Qvarn.
-
-* Ian makes a release.
-
- * Ian clones Qvarn.
- * Ian tags the right commit with a release tag.
- * Ian pushes the tag to the git server.
- * CI updates its own git clone; new release tag triggers a release
- build.
-
-* Olive provisions a new Qvarn instance.
-
- * Olive clones a repository with Ansible playbooks.
- * Olive clones a repository with encrypted passowords.
- * Olive creates a local branch in the Ansible playbooks.
- * Olive makes and commits any necessary changes to the playbooks.
- * Olive creates a new VM and runs Ansible.
- * Olive pushes her new local branch to the server for review.
- * After revies feedback, Olive merges her changes to master.
- * Olive pushes master changes to server.
-
-* Steven updates internal wiki.
-
- * Steven clones intrawiki.git.
- * Steven makes changes.
- * Steven commits changes to local master branch.
- * Steven pushes master changes to git server.
- * CI notices changes and updated intrawiki website.
-
-* Gabriella makes a bug fix.
-
- * Gabriella clones qvarn.git.
- * Gabriella creates a new branch.
- * Gabriella changes new branch to fix bug.
- * Gabriella pushes new branch to git server.
- * Gabriella notifies others of new branch.
- * Ian reviews branch and finds it good.
- * Ian merges branch to master.
- * CI notices change in master and runs a CI pipeline.
-
-* JR makes a bug fix.
-
- * JR clones qvarn.git.
- * JR creates a new local branch.
- * JR fixes bug in local branch.
- * JR pushes local branch to his own git server.
- * JR notifies others of changes on his git server.
- * Ian reviews changes from JR'r server, merges them to master from
- git.qvarnlabs.net, and pushes new master to git.q.n.
- * CI notices changes to master and runs CI pipeline.
-
-* Anyone but Olive tries to clone the secrets repository
-
- * Gabriella attempts to clone the secrets repository.
- * The attempt fails.
-
-* Tina adds a feature to another project, matching unreleased changes
- to Qvarn.
-
- * Tina clones qvarn.git.
- * Tina clones other-project.git.
- * Tina makes a change in other-project.git.
- * Tina pushes change in master to tina-project.git.
+[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 at some
- level. Private may mean private to all staff or private to only
- specific people (e.g., ops secrets).
+ 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 write access to some repositories, whereas
- everyone else (even with Gitano accounts) have only read access to
- those respositories. Example, Steven doesn't need write access to
- the Qvarn repository, but there's no point in restricting read
- access, since it's a public repository.
+* 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. This prevents Gary from making
- releases, or changing master without anyone else knowing about it.
+ themselves, or create release tags. We call these guests.
-Some principles/suggestions
------------------------------------------------------------------------------
-
-* There's several groups of people. Each group needs different access.
+* 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.)
- - implicitly trusted staff members (those who can do ops)
- - normal staff members (Steven)
- - outsider guest users (Gabriella)
- - automated systems (CI)
-
-* Three types of repositories.
+Rough outline for ruleset
+-----------------------------------------------------------------------------
- - completely public (qvarn.git)
- - private, but public to staff (intrawiki.git)
- - accessible to just part of staff (ops secrets)
+* Only a Gitano admin can create users, groups, and repositories, or
+ add users to groups.
-* Guests should be able to update public repos in restricted ways.
+* 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.
- - they may only create/modify branches that are not used by
- others, e.g., their names are prefixed by their Gitano username
- - they may only create tags not used by others (again, prefixed),
- so that they may not create release tags
+ For example, if `qvarn.git` has `writers` defined as
+ `qvarnlabs-staff`, then only those in the `qvarnlabs-staff` group
+ have full write access.
-* Staff is either developers or otherwise trusted (i.e., can modify
- any branches, can make any tags), or treated the same as guests.
+* All groups have full read access. (Git doesn't really allow limiting
+ read at a more granular scale than a repository.)
-* Even staff may only have full access to some repos (qvarn.git), but
- not all (ops ones). For the latter, treat them similar to guests.
+* Writers have full write access. They can push changes, and update
+ any branches and tags.
-* CI and other automated systems only have read-only access. If an
- automated system needs write access later, consider the implications
- at that time.
-
-Rough outline for ruleset
------------------------------------------------------------------------------
-
-* All repositories should have three configuration variables,
- `readers`, `writers`, and `guests`. The value of each varibable is
- the name of a Gitano group. Access is granted to users in the named
- group.
+* 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.
+ them, and cgit shows them to anyone. Public repositories are
+ published via the anonymous git prototocol.
-Scenarios
------------------------------------------------------------------------------
+Use cases as automated test scenarios
+=============================================================================
-These [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
+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/
-This is going to be a long scenario, but that's just so that we don't
-need to re-do the setup. The setup consists of creating test users,
-groups, and respositories.
+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
@@ -215,6 +118,9 @@ groups, and respositories.
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
@@ -229,6 +135,9 @@ groups, and respositories.
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
@@ -244,6 +153,9 @@ groups, and respositories.
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
@@ -257,6 +169,9 @@ groups, and respositories.
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
@@ -271,27 +186,44 @@ groups, and respositories.
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
+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))
+ 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)
+ 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()
@@ -299,10 +231,17 @@ groups, and respositories.
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))
+ output = helper.gitano(
+ None, 'group adduser {} {}'.format(group, user))
+
+WHEN admin created repository
+-----------------------------------------------------------------------------
IMPLEMENTS WHEN admin creates repository (\S+)
repo = helper.get_next_match()
@@ -323,12 +262,18 @@ groups, and respositories.
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()
@@ -338,6 +283,9 @@ groups, and respositories.
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()
@@ -346,6 +294,9 @@ groups, and respositories.
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']
@@ -353,6 +304,9 @@ groups, and respositories.
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()
@@ -360,6 +314,9 @@ groups, and respositories.
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()
@@ -370,6 +327,9 @@ groups, and respositories.
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()
@@ -377,6 +337,9 @@ groups, and respositories.
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()
@@ -384,6 +347,9 @@ groups, and respositories.
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()
@@ -395,6 +361,9 @@ groups, and respositories.
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()
@@ -404,6 +373,9 @@ groups, and respositories.
['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()
@@ -413,6 +385,9 @@ groups, and respositories.
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()
@@ -421,6 +396,9 @@ groups, and respositories.
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, [])