summaryrefslogtreecommitdiff
path: root/000.yarn
diff options
context:
space:
mode:
Diffstat (limited to '000.yarn')
-rw-r--r--000.yarn286
1 files changed, 286 insertions, 0 deletions
diff --git a/000.yarn b/000.yarn
new file mode 100644
index 0000000..7f72fc9
--- /dev/null
+++ b/000.yarn
@@ -0,0 +1,286 @@
+---
+title: "A Gitano ruleset: tests"
+author: Lars Wirzenius (liw@liw.fi)
+date: 2017-02-04
+...
+
+[Gitano][] is the server software I use for my personal git server,
+and also for work. One of Gitano's primary features is a strong
+language for defining access control, called [Lace][]. However, with
+great power comes long shoelaces to tie together. This document
+explains what my rules set 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/
+
+
+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.
+
+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).
+
+* 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.
+
+* 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.
+
+Some principles/suggestions
+-----------------------------------------------------------------------------
+
+* There's several groups of people. Each group needs different access.
+
+ - implicitly trusted staff members (those who can do ops)
+ - normal staff members (Steven)
+ - outsider guest users (Gabriella)
+ - automated systems (CI)
+
+* Three types of repositories.
+
+ - completely public (qvarn.git)
+ - private, but public to staff (intrawiki.git)
+ - accessible to just part of staff (ops secrets)
+
+* Guests should be able to update public repos in restricted ways.
+
+ - 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
+
+* Staff is either developers or otherwise trusted (i.e., can modify
+ any branches, can make any tags), or treated the same as guests.
+
+* 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.
+
+* 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.
+
+* 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.
+
+
+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
+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.
+
+ SCENARIO create users, groups, repositories
+ WHEN we run gitano whoami
+ THEN we are in group gitano-admin
+
+<!--
+
+ WHEN we create user ian
+ AND we create user olive
+ AND we create user steven
+ AND we create user gabriella
+ AND we create user tina
+ AND we create user ci
+
+ WHEN we create group qvarndevs
+ AND we create group qvarnguests
+ AND we create group ops
+ AND we create group otherdevs
+ AND we create group staff
+
+ WHEN we add ian to qvarndevs
+ AND we add tina to qvarndevs
+ AND we add gabriells to qvarnguests
+ AND we add olive to ops
+ AND we add tina to otherdevs
+ AND we add steven to staff
+
+ WHEN we create repository qvarn
+ AND we create repository ops/secrets
+ AND we create repository ops/ansible
+ AND we create repository intrawiki
+ AND we create repository otherproject
+
+ WHEN we set qvarn config writers to qvarndevs
+ AND we set qvarn config guests to qvarnguests
+ AND we set qvarn config public to yes
+ AND we set ops/secrets config writers to ops
+ AND we set ops/ansible config writers to ops
+ AND we set intrawiki config writers to staff
+
+Now we can start defining use cases.
+
+Use case: Ian makes a bugfix to Qvarn.
+
+ WHEN ci clonse qvarn
+ AND ian clones qvarn
+ AND ian creates local qvarn branch ian/bugfix
+ AND ian pushes qvarn
+ AND ian merges ian/bugfix into master
+ AND ian pushes qvarn
+ THEN ci sees new commit in qvarn
+
+Use case: Ian makes a release.
+
+ WHEN ian creates tag qvarn-1.0 in qvarn master
+ AND ian pushes qvarn
+ THEN ci sees tag qvarn-1.0 in qvarn
+
+Use case: Olive provisions a new Qvarn instance.
+
+ WHEN olive clones ops/ansible
+ AND olive clones ops/secrets
+ AND olive creates local ops/ansible branch newthing
+ AND olive pushes ops/ansible
+ AND merges ops/ansible branch newthing to master
+ AND olive pushes ops/ansible
+
+Use case: Steven updates internal wiki.
+
+ WHEN ci clones intrawiki
+ AND steven clones intrawiki
+ AND steven makes a change in intrawiki master
+ AND steven pushes intrawiki
+ THEN ci sees a new commit in intrawiki
+
+-->
+
+
+# Scenario step implementations
+
+ IMPLEMENTS WHEN we run gitano (.+)
+ args = helper.get_next_match()
+ whoami_output = helper.gitano(args)
+ helper.set_variable('admin_whoami', whoami_output)
+
+ IMPLEMENTS THEN we are in group gitano-admin
+ whoami = helper.get_variable('admin_whoami')
+ helper.assertIn('gitano-admin', whoami)