From fb652434121c382fc622845ec714c2a14f2fde58 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Fri, 7 Sep 2012 14:29:43 +0100 Subject: Initial ruleset and beginnings of gitano-admin overlay --- gitano-admin/global-hooks/post-receive.lua | 94 ++++++++++++++++++++++++++++++ gitano-admin/rules/adminchecks.lace | 18 ++++++ gitano-admin/rules/aschecks.lace | 14 +++++ gitano-admin/rules/core.lace | 36 ++++++++++++ gitano-admin/rules/createrepo.lace | 15 +++++ gitano-admin/rules/ct-project.lace | 20 +++++++ gitano-admin/rules/defines.lace | 82 ++++++++++++++++++++++++++ gitano-admin/rules/destroyrepo.lace | 9 +++ gitano-admin/rules/project.lace | 22 +++++++ gitano-admin/rules/remoteconfigchecks.lace | 9 +++ gitano-admin/rules/renamerepo.lace | 6 ++ gitano-admin/rules/selfchecks.lace | 5 ++ gitano-admin/rules/siteadmin.lace | 22 +++++++ mason-notify.post-receive.lua | 94 ------------------------------ 14 files changed, 352 insertions(+), 94 deletions(-) create mode 100644 gitano-admin/global-hooks/post-receive.lua create mode 100644 gitano-admin/rules/adminchecks.lace create mode 100644 gitano-admin/rules/aschecks.lace create mode 100644 gitano-admin/rules/core.lace create mode 100644 gitano-admin/rules/createrepo.lace create mode 100644 gitano-admin/rules/ct-project.lace create mode 100644 gitano-admin/rules/defines.lace create mode 100644 gitano-admin/rules/destroyrepo.lace create mode 100644 gitano-admin/rules/project.lace create mode 100644 gitano-admin/rules/remoteconfigchecks.lace create mode 100644 gitano-admin/rules/renamerepo.lace create mode 100644 gitano-admin/rules/selfchecks.lace create mode 100644 gitano-admin/rules/siteadmin.lace delete mode 100644 mason-notify.post-receive.lua diff --git a/gitano-admin/global-hooks/post-receive.lua b/gitano-admin/global-hooks/post-receive.lua new file mode 100644 index 0000000..bb23ec4 --- /dev/null +++ b/gitano-admin/global-hooks/post-receive.lua @@ -0,0 +1,94 @@ +-- mason-notify.post-receive.lua +-- +-- Global post-receive hook which notifies Mason of any and all refs updates +-- (except refs/gitano/*) which happen. +-- +-- It notifies Mason *before* passing the updates on to the project hook. +-- +-- Copyright 2012 Codethink Limited +-- +-- This is a part of Trove and re-use is limited to Baserock systems only. +-- + +local project_hook, repo, updates = ... + +local masonhost = "##MASON_HOST##:##MASON_PORT##" +local basepath = "/1.0" +local urlbases = { + "git://##TROVE_HOSTNAME##/", + "ssh://git@##TROVE_HOSTNAME##/", +} + +local notify_mason = false + +for ref in pairs(updates) do + if not ref:match("^refs/gitano/") then + notify_mason = true + end +end + +if notify_mason and repo.name ~= "gitano-admin" then + -- Build the report... + local masoninfo, indent_level = {}, 0 + local function _(...) + masoninfo[#masoninfo+1] = (" "):rep(indent_level) .. table.concat({...}) + end + local function indent() + indent_level = indent_level + 1 + end + local function dedent() + indent_level = indent_level - 1 + end + _ "{" indent() + + _ '"urls": [' indent() + + for i = 1, #urlbases do + local comma = (i==#urlbases) and "" or "," + _(("%q,"):format(urlbases[i] .. repo.name) + _(("%q%s"):format(urlbases[i] .. repo.name .. ".git", comma)) + end + + dedent() _ "]," + + _ '"changes": [' indent() + + local toreport = {} + for ref, info in pairs(updates) do + if not ref:match("^refs/gitano") then + toreport[#toreport+1] = { + ('"ref": %q,'):format(ref), + ('"old": %q,'):format(info.oldsha), + ('"new": %q'):format(info.newsha) + } + end + end + for i = 1, #toreport do + local comma = (i==#toreport) and "" or "," + _ "{" indent() + for __, ent in ipairs(toreport[i]) do + _(ent) + end + dedent() _("}", comma) + end + dedent() _ "]" + + dedent() _ "}" + + -- And finalise the JSON object + _("") + masoninfo = table.concat(masoninfo, "\n") + log.state("Notifying Mason of changes...") + + local code, msg, headers, content = + http.post(masonhost, basepath, "application/json", masoninfo) + if code ~= "200" then + log.state("Notification failed somehow") + end + for line in content:gmatch("([^\r\n]*)\r?\n") do + log.state("Mason: " .. line) + end +end + +-- Finally, chain to the project hook +return project_hook(repo, updates) diff --git a/gitano-admin/rules/adminchecks.lace b/gitano-admin/rules/adminchecks.lace new file mode 100644 index 0000000..9d4864b --- /dev/null +++ b/gitano-admin/rules/adminchecks.lace @@ -0,0 +1,18 @@ +# Core project administration rules + +# Called with ref known to be refs/gitano/admin + +# Administrators already got to do anything, so this is for non-admins + +# Non-admin members may not delete the admin ref +deny "Non-administrators may not delete the admin ref" op_deleteref + +# Otherwise, the project's owner is allowed to alter the admin tree +allow "Project owner may alter the admin ref" is_owner + +# Project admins may alter admin +allow "Project admins may alter the admin ref of project repos" repo_has_project_code ct_admin + +# Any other opportunities for altering the admin ref must be provided +# by the project's rules + \ No newline at end of file diff --git a/gitano-admin/rules/aschecks.lace b/gitano-admin/rules/aschecks.lace new file mode 100644 index 0000000..2fb2ae6 --- /dev/null +++ b/gitano-admin/rules/aschecks.lace @@ -0,0 +1,14 @@ +# Rules for when we're running as another user. +# Only 'deny' things which are not allowed. +# If you 'allow' then it will allow the actual operation, not just +# fail to deny the fact that it's 'as' someone else. + +define as_is_admin as_group gitano-admin + +# ct-admin members are permitted to run sshkey and whoami on behalf of others +define as_is_ct_admin as_group ct-admin +define as_ct_admin_ok allof as_is_ct_admin op_self + +define as_is_ok anyof as_is_admin as_ct_admin_ok + +deny "You may not run things as another user unless you are an admin" !as_is_ok diff --git a/gitano-admin/rules/core.lace b/gitano-admin/rules/core.lace new file mode 100644 index 0000000..351fbda --- /dev/null +++ b/gitano-admin/rules/core.lace @@ -0,0 +1,36 @@ +# Prepare the initial definitions + +default deny "The ruleset didn't provide access. Denying by default." + +include global:defines + +# Now, if we're in the admin group, we can always do stuff +allow "Administrators can do anything" is_admin !if_asanother + +# Now let's decide if we can use 'as' +include global:aschecks if_asanother + +# Operations which are against 'self' get checked next +include global:selfchecks + +# Administration operations (users, groups) next +include global:siteadmin op_is_admin + +# Site-defined rules for repository creation +include global:createrepo op_createrepo + +# Site-defined rules for repository renaming +include global:renamerepo op_renamerepo + +# Site-defined rules for repository destruction +include global:destroyrepo op_destroyrepo + +# Site-defined rules for project repositories, including admin of them +include global:project + +# Now the project rules themselves +include main + +# Now, if you want to allow anonymous access if the project doesn't prevent +# it, then you can uncomment the following: +# allow "Anonymous access is okay" op_read !is_admin_repo diff --git a/gitano-admin/rules/createrepo.lace b/gitano-admin/rules/createrepo.lace new file mode 100644 index 0000000..ef1bffc --- /dev/null +++ b/gitano-admin/rules/createrepo.lace @@ -0,0 +1,15 @@ +# Rules related to creating repositories + +# Administrators have already been permitted whatever they like +# so this is for non-admins. + +# Uncomment the following to allow repositories in personal/username/ + +define repo_is_personal repository ~^people/${user}/ +allow "Personal repo creation is okay" repo_is_personal + +# Allow people in ctxxx-admins to create repositories under ctxxx +allow "Project admins may make project repositories" repo_has_project_code ct_admin + +# Otherwise the default is that non-admins can't create repositories +deny "Repository creation is not permitted." diff --git a/gitano-admin/rules/ct-project.lace b/gitano-admin/rules/ct-project.lace new file mode 100644 index 0000000..e1f6696 --- /dev/null +++ b/gitano-admin/rules/ct-project.lace @@ -0,0 +1,20 @@ +# Rules for ctxxx/... repositories + +# Reading the repository +allow "Readers gonna read" op_read ct_reader +deny "This repository not for you" op_read + +# Basic writes to the repo +allow "Writers gonna write" op_write ct_writer +deny "This repository not for you" op_write + +# Ref based rules for the repo + +## Master +allow "Master may be created" op_createref master_ref +allow "Master may be altered" op_is_update master_ref +deny "Master may not be deleted" op_deleteref master_ref + +## Anything else. +allow "Writers gonna write" op_is_reffy !master_ref + diff --git a/gitano-admin/rules/defines.lace b/gitano-admin/rules/defines.lace new file mode 100644 index 0000000..b6df4c5 --- /dev/null +++ b/gitano-admin/rules/defines.lace @@ -0,0 +1,82 @@ +# A useful set of defines + +# User/group related +define is_admin group gitano-admin +define is_owner owner ${user} + +define if_asanother as_user ~. + +# Self-related operations +define op_whoami operation whoami +define op_sshkey operation sshkey +define op_self anyof op_whoami op_sshkey + +# Admin-related operations + +## Users +define op_useradd operation useradd +define op_userdel operation userdel +define op_userlist operation userlist +define op_useremail operation useremail +define op_username operation username +define op_user anyof op_userlist op_useradd op_userdel op_useremail op_username + +## Groups +define op_grouplist operation grouplist +define op_groupshow operation groupshow +define op_groupadd operation groupadd +define op_groupdel operation groupdel +define op_groupadduser operation groupadduser +define op_groupdeluser operation groupdeluser +define op_groupaddgroup operation groupaddgroup +define op_groupdelgroup operation groupdelgroup +define op_groupdescription operation groupdescription +define op_group anyof op_grouplist op_groupshow op_groupadd op_groupdel op_groupadduser op_groupdeluser op_groupaddgroup op_groupdelgroup op_groupdescription + +## Aggregation of admin ops +define op_is_admin anyof op_user op_group + +# Primary repository-related operations +define op_read operation read +define op_write operation write +define op_createrepo operation createrepo +define op_renamerepo operation renamerepo +define op_destroyrepo operation destroyrepo + +# Remote configuration operations +define op_config_show operation config_show +define op_config_set operation config_set +define op_config_del operation config_del +define op_is_config anyof op_config_show op_config_set op_config_del + +# Reference update related operations +define op_createref operation createref +define op_deleteref operation deleteref +define op_fastforward operation updaterefff +define op_forcedupdate operation updaterefnonff + +# Combinator operations +define op_is_basic anyof op_read op_write +define op_is_update anyof op_fastforward op_forcedupdate +define op_is_normal anyof op_fastforward op_createref op_deleteref + +# Administration +define is_admin_repo repository gitano-admin +define is_gitano_ref ref ~^refs/gitano/ +define is_admin_ref ref refs/gitano/admin + +# Codethink defines: + +define repo_has_project_code repository ~^ct[0-9]+/ + +define ct_reader group ${repository/1}-readers +define ct_writer group ${repository/1}-writers +define ct_admin group ${repository/1}-admins + +define master_ref ref ~^refs/heads/master$ + +define op_is_reffy anyof op_is_normal op_forcedupdate + +define ct_site_admin group ct-admin + +define target_group_gitano_admin targetgroup gitano-admin diff --git a/gitano-admin/rules/destroyrepo.lace b/gitano-admin/rules/destroyrepo.lace new file mode 100644 index 0000000..fb2d494 --- /dev/null +++ b/gitano-admin/rules/destroyrepo.lace @@ -0,0 +1,9 @@ +# Rules related to the destroying of repositories + +# For now, owners may destroy repositories +allow "You may destroy your own repositories" is_owner + +# Admins may destroy repos inside their projects +allow "Project admins may destroy project repos" repo_has_project_code ct_admins + +deny "You may not destroy repositories you do not own" diff --git a/gitano-admin/rules/project.lace b/gitano-admin/rules/project.lace new file mode 100644 index 0000000..b09ad10 --- /dev/null +++ b/gitano-admin/rules/project.lace @@ -0,0 +1,22 @@ +# Core project administration rules + +# Admins already got allowed, so this is for non-admin users only +allow "Owners can always read and write" op_is_basic is_owner + +# Uncomment if you want to *force* anonymous access to all but gitano-admin +# allow "Anonymous access always allowed" op_read !is_admin_repo + +# Project remote-configuration rules (set-head etc) +include global:remoteconfigchecks op_is_config + +# Okay, if we're altering the admin ref, in we go +include global:adminchecks is_admin_ref + +# Now we're into branch operations. Owners can do any normal operation +# Normal ops are create/delete/fastforward on refs +allow "Owners can create refs" op_is_normal is_owner +# We don't enable non-fastforward updates by default. Projects must do +# this in their own rules if they want it. + + +include global:ct-project repo_has_project_code diff --git a/gitano-admin/rules/remoteconfigchecks.lace b/gitano-admin/rules/remoteconfigchecks.lace new file mode 100644 index 0000000..80cf802 --- /dev/null +++ b/gitano-admin/rules/remoteconfigchecks.lace @@ -0,0 +1,9 @@ +# Remote config checks + +# Owners may do any remote admin operation they choose +allow "Owners may remote-admin their repositories" is_owner + +# ctxxx-admins may remote-admin ctxxx repositories +allow "Project admins may admin project repos" repo_has_project_code ct_admins + +deny "You may not configure this repository remotely" diff --git a/gitano-admin/rules/renamerepo.lace b/gitano-admin/rules/renamerepo.lace new file mode 100644 index 0000000..946d544 --- /dev/null +++ b/gitano-admin/rules/renamerepo.lace @@ -0,0 +1,6 @@ +# Rules related to renaming repositories + +# For now, owners may rename their repositories +allow "Owners may rename repositories" op_renamerepo is_owner + +deny "You may not rename a repository you do not own" diff --git a/gitano-admin/rules/selfchecks.lace b/gitano-admin/rules/selfchecks.lace new file mode 100644 index 0000000..300bb91 --- /dev/null +++ b/gitano-admin/rules/selfchecks.lace @@ -0,0 +1,5 @@ +# Checks against self + +allow "You may ask who you are" op_whoami + +allow "You may manage your own ssh keys" op_sshkey diff --git a/gitano-admin/rules/siteadmin.lace b/gitano-admin/rules/siteadmin.lace new file mode 100644 index 0000000..b3818ef --- /dev/null +++ b/gitano-admin/rules/siteadmin.lace @@ -0,0 +1,22 @@ +# Site administration rules + +# You must explicitly allow site administration here for anyone who +# has the rights to do site admin but isn't a member of gitano-admin. + +# ct_site_admin is a predicate which is for ct-admin +allow "CT Site Admins can manage users" ct_site_admin op_user +allow "CT Site Admins can manage groups other than gitano-admin" ct_site_admin op_group !target_group_gitano_admin + +# ctXXX-admins members are permitted to edit ctXXX-* groups +define ct_may_admin_target_group group ${targetgroup/prefix}-admins +define is_ct_project_target targetgroup ~^ct[0-9]+%- +allow "CT project admins can manage ctXXX- groups for their projects" op_group is_ct_project_target ct_may_admin_target_group + +# Anyone is permitted to look at the people in ct-admin and ctXXX-admins +define ct_target_group_is_ct_admin targetgroup ct-admin +define ct_target_group_is_ctxxx_admins targetgroup ~^ct[0-9]+%-admins$ +define ct_show_target_ok anyof ct_target_group_is_ct_admin ct_target_group_is_ctxxx_admins +allow "Anyone may see admin groups" op_groupshow ct_show_target_ok + +# Otherwise we always deny site administration +deny "You may not perform site administration" diff --git a/mason-notify.post-receive.lua b/mason-notify.post-receive.lua deleted file mode 100644 index bb23ec4..0000000 --- a/mason-notify.post-receive.lua +++ /dev/null @@ -1,94 +0,0 @@ --- mason-notify.post-receive.lua --- --- Global post-receive hook which notifies Mason of any and all refs updates --- (except refs/gitano/*) which happen. --- --- It notifies Mason *before* passing the updates on to the project hook. --- --- Copyright 2012 Codethink Limited --- --- This is a part of Trove and re-use is limited to Baserock systems only. --- - -local project_hook, repo, updates = ... - -local masonhost = "##MASON_HOST##:##MASON_PORT##" -local basepath = "/1.0" -local urlbases = { - "git://##TROVE_HOSTNAME##/", - "ssh://git@##TROVE_HOSTNAME##/", -} - -local notify_mason = false - -for ref in pairs(updates) do - if not ref:match("^refs/gitano/") then - notify_mason = true - end -end - -if notify_mason and repo.name ~= "gitano-admin" then - -- Build the report... - local masoninfo, indent_level = {}, 0 - local function _(...) - masoninfo[#masoninfo+1] = (" "):rep(indent_level) .. table.concat({...}) - end - local function indent() - indent_level = indent_level + 1 - end - local function dedent() - indent_level = indent_level - 1 - end - _ "{" indent() - - _ '"urls": [' indent() - - for i = 1, #urlbases do - local comma = (i==#urlbases) and "" or "," - _(("%q,"):format(urlbases[i] .. repo.name) - _(("%q%s"):format(urlbases[i] .. repo.name .. ".git", comma)) - end - - dedent() _ "]," - - _ '"changes": [' indent() - - local toreport = {} - for ref, info in pairs(updates) do - if not ref:match("^refs/gitano") then - toreport[#toreport+1] = { - ('"ref": %q,'):format(ref), - ('"old": %q,'):format(info.oldsha), - ('"new": %q'):format(info.newsha) - } - end - end - for i = 1, #toreport do - local comma = (i==#toreport) and "" or "," - _ "{" indent() - for __, ent in ipairs(toreport[i]) do - _(ent) - end - dedent() _("}", comma) - end - dedent() _ "]" - - dedent() _ "}" - - -- And finalise the JSON object - _("") - masoninfo = table.concat(masoninfo, "\n") - log.state("Notifying Mason of changes...") - - local code, msg, headers, content = - http.post(masonhost, basepath, "application/json", masoninfo) - if code ~= "200" then - log.state("Notification failed somehow") - end - for line in content:gmatch("([^\r\n]*)\r?\n") do - log.state("Mason: " .. line) - end -end - --- Finally, chain to the project hook -return project_hook(repo, updates) -- cgit v1.2.1