# # add_dir "" # # add_file "README" # content [c89ddcc4c84537e3e1143636bca5ccffb2a8ec18] # # add_file "policy.lua" # content [3ed30ce0d9b82372c8ea5cf2bfdd12bf1d620659] # # add_file "update-policy.lua" # content [c28a583b181f9b63f931236d97a118f1bc1f2bf6] --- README +++ README @@ -0,0 +1,71 @@ +This is a policy branch implementation written with Lua hooks and scripts. +To use it, check it out into your .monotone or copy the files there, and +include policy.lua in your monotonerc. + +Other interesting files (all under policy/) are: + override-write-permissions + If this file exists, it will be used in place of the allowed writers + computed from the policy branches. It will be used in addition to the + normal write-permissions file. + + override-servers + If this file exists, it will be used in place of the server list + computed from the policy branches, to determine what servers to + forward what branches to. + + cache/write-permissions + A normal write-permissions file, constructed from the combined + write-permissions of all policy branches. + + cache/all-servers + This contains lines of + server "address" "key" "prefix" + , and is used by the server to know which other servers to forward + received revisions to. Note that individual certs may not be forwarded + until a branch cert matching "prefix" is received. + + cache/all-policy-branches + This contains a list of all used policy branches. + + self/ + A directory that looks exactly like a normal policy branch. + + +A policy branch contains the following files: + + write-permissions + A normal write-permissions file, listing people who should have write + access to this set of branches. + + servers + A list of + server "address" "key" + or + server "address" "key" "prefix" + lines. If "prefix" is absent, it is taken to be whatever was delegated + to this policy branch. If "prefix" is not under whatever prefix was + delegated to this branch, that line is ignored. + + delegations + This determines which policy branches will be used for which branch + groups. It contains stanzas of + delegate "prefix" "policy.branch" + admin "key1" + admin "key2" + . Branches equal to "prefix" or matching "prefix.*" will be associated + with policy branch "policy.branch", and keys "key1", "key2" will be + allowed to commit revisions to "policy.branch". + + delegations.d/prefix/ + There is one directory like this for each prefix delegated to another + policy branch. + + delegations.d/prefix/self/ + This is a checkout of the policy branch to which the prefix is delegated. + It is NOT present in the policy branch itself, but is created and + maintained on disk by the policy scripts. + + delegations.d/prefix/override-servers + delegations.d/prefix/override-write-permissions + This files (if present) allow the policy branch to ignore parts of the + policy of the branches it delegates to. --- policy.lua +++ policy.lua @@ -0,0 +1,143 @@ +-- utility functions, could be moved to std_hooks.lua +function read_conffile(name) + return read_contents_of_file(get_confdir() .. "/" .. name, "r") +end + +function read_basic_io_conffile(name) + local dat = read_conffile(name) + if dat == nil then return nil, false end + return parse_basic_io(dat), true +end + +function conffile_iterator(name) + local out = {} + out.file = io.open(get_confdir() .. "/" .. name, "r") + if out.file == nil then return nil, false end + local mt = {} + mt.__index = mt + mt.get = function() + if out.file == nil then return nil end + out.line = out.file:read() + return out.line + end + mt.close = function() + if out.file == nil then return end + io.close(out.file) + end + return setmetatable(out, mt), true +end + +function trim(str) + local _,_,r = string.find(str, "%s*([^%s]*)%s*") + return r +end + +------------------------------------------------------------------------ + +function branch_in_prefix(branch, prefix) + if branch == prefix then + return true + end + if string.sub(branch, 1, string.len(prefix)+1) == prefix .. '.' then + return true + end + return false +end + +do + local old_write_permitted = get_netsync_write_permitted + function get_netsync_write_permitted(ident) + local committers, ok + committers, exists = conffile_iterator("policy/override-write-permissions") + if not exists then + committers = conffile_iterator("policy/cache/write-permissions") + end + if committers ~= nil then + while committers:get() do + if globish_match(trim(committers.line), ident) then + committers:close() + return true + end + end + committers:close() + end + return old_write_permitted(ident) + end +end + +function push_to_other_servers(triggerkey, branches) + local data, exists + data, exists = read_basic_io_conffile("policy/override-all-servers") + if not exists then + data, exists = read_basic_io_conffile("policy/cache/all-servers") + end + if not exists then return end + if data == nil then + io.stderr:write("server list file cannot be parsed\n") + return + end + + local pushto = {} + + for i, item in pairs(data) + do + if item.name == "server" then + if item.values[2] == triggerkey + then + return + end + end + end + + + for i, item in pairs(data) + do + if item.name == "server" then + server_request_sync("sync", item.values[1], + include, exclude) + end + end +end + + +function note_netsync_start(sid, role, what, rhost, rkey, include, exclude) + if sessions == nil then sessions = {} end + sessions[sid] = { + key = rkey, + branches = {}, + include = include, + exclude = exclude + } +end + +function note_netsync_revision_received(rid, rdat, certs, sid) + for _, cert in pairs (certs) do + if cert.name == "branch" then + sessions[sid].branches[cert.value] = true + end + end +end + +function note_netsync_cert_received(rid, key, name, value, sid) + if name == "branch" then + sessions[sid].branches[value] = true + end +end + +function note_netsync_end(sid, status, bi, bo, ci, co, ri, ro, ki, ko) + if ci > 0 or ri > 0 or ki > 0 then + server_maybe_request_sync(sessions[sid].key) + elseif sessions[sid].include == '' and + sessions[sid].exclude == 'ctl-branch-updated' then + log("resyncing after a config update...") + server_maybe_request_sync('') + end + + -- Do we update the control checkout? + local ctlbranch = trim(read_conffile("serverctl-branch")) + if ctlbranch and sessions[sid].branches[ctlbranch] then + log("updating configuration...") + execute(get_confdir() .. "/serverctl-update.sh", get_confdir()) + end + sessions[sid] = nil +end--- update-policy.lua +++ update-policy.lua @@ -0,0 +1,2 @@ +-- hooks used when updating the policy branches +-- looks at the DELEGATIONS and PREFIX env vars