From 32b09256150d139e77d04533f28d0c26a32b12bd Mon Sep 17 00:00:00 2001 From: KatolaZ Date: Tue, 11 Jul 2017 14:38:55 +0100 Subject: added notes.txt on the architecture, and a sample worker_config --- commits.go | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ config.go | 2 +- notes.txt | 54 +++++++++++++++++++++++++++++ scorsh.go | 11 +++--- worker_config.cfg | 37 ++++++++++++++++++++ 5 files changed, 198 insertions(+), 7 deletions(-) create mode 100644 commits.go create mode 100644 notes.txt create mode 100644 worker_config.cfg diff --git a/commits.go b/commits.go new file mode 100644 index 0000000..c429bca --- /dev/null +++ b/commits.go @@ -0,0 +1,101 @@ +package main + +import ( + "fmt" + "github.com/KatolaZ/git2go" + "golang.org/x/crypto/openpgp" + "os" + "strings" + "log" +) + +func CommitToString(commit *git.Commit) string { + + var ret string + + ret += fmt.Sprintf("type: %s\n", commit.Type()) + ret += fmt.Sprintf("Id: %s\n", commit.Id()) + ret += fmt.Sprintf("Author: %s\n", commit.Author()) + ret += fmt.Sprintf("Message: %s\n", commit.Message()) + ret += fmt.Sprintf("Parent-count: %d\n", commit.ParentCount()) + + return ret +} + +// FIXME: RETURN THE ENTITY PROVIDED BY THE CHECK, OR nil +func check_signature(commit *git.Commit, keyring *openpgp.KeyRing) (signature, signed string, err error) { + + signature, signed, err = commit.ExtractSignature() + if err == nil { + + _, err_sig := + openpgp.CheckArmoredDetachedSignature(*keyring, strings.NewReader(signed), + strings.NewReader(signature)) + + if err_sig == nil { + fmt.Printf("Good signature \n") + return signature, signed, nil + } + err = err_sig + } + + return "", "", err +} + + +// traverse all the commits between two references, looking for scorsh +// commands +// fixme: we don't have just one keyring here.... +func walk_commits(msg SCORSHmsg, keyring openpgp.KeyRing) int { + + fmt.Printf("Inside parse_commits\n") + + reponame := msg.repo + old_rev := msg.old_rev + new_rev := msg.new_rev + + repo, err := git.OpenRepository(reponame) + if err != nil { + fmt.Fprintf(os.Stderr, "Error while opening repository %s (%s)\n", + reponame, err) + return SCORSH_ERR_NO_REPO + } + + old_rev_oid, err := git.NewOid(old_rev) + + oldrev_commit, err := repo.LookupCommit(old_rev_oid) + if err != nil { + fmt.Fprintf(os.Stderr, "Commit: %s does not exist\n", old_rev) + return SCORSH_ERR_NO_COMMIT + } + + new_rev_oid, err := git.NewOid(new_rev) + + newrev_commit, err := repo.LookupCommit(new_rev_oid) + if err != nil { + fmt.Fprintf(os.Stderr, "Commit: %s does not exist\n", new_rev) + return SCORSH_ERR_NO_COMMIT + } + + cur_commit := newrev_commit + + for cur_commit.Id().String() != oldrev_commit.Id().String() { + + commit, err := repo.LookupCommit(cur_commit.Id()) + if err == nil { + + fmt.Printf("%s", CommitToString(commit)) + //signature, signed, err := check_signature(commit, &keyring) + _, _, err := check_signature(commit, &keyring) + if err != nil { + log.Printf("%s\n", SCORSHErr(SCORSH_ERR_SIGNATURE)) + + } + cur_commit = commit.Parent(0) + } else { + fmt.Printf("Commit %x not found!\n", cur_commit.Id()) + return SCORSH_ERR_NO_COMMIT + } + } + return 0 +} diff --git a/config.go b/config.go index 6d8786f..452f187 100644 --- a/config.go +++ b/config.go @@ -28,7 +28,7 @@ type SCORSHcfg struct { // Read a configuration from fname or die -func ReadConfig(fname string) *SCORSHcfg { +func ReadGlobalConfig(fname string) *SCORSHcfg { data, err := ioutil.ReadFile(fname) if err != nil { diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..618fcbf --- /dev/null +++ b/notes.txt @@ -0,0 +1,54 @@ +## structure + +- we read the list of workers from the config file. Each worker + record consists of + + - a list of repos/branches + - a folder where the configs and logs are kept + - a logfile + - a tagfile with the definition of tags + - a list of keyring files + +## master logic + +- in main() (master) we create a worker for each worker record, + maintaining a map of which worker can process commands for which + repo/branch + +- The spooler receives and processes CREATE events from the spool. It + parses each message and forwards it to the corresponding worker(s). + +- When the worker is done, it notifies the master, which will delete + the corresponding file from the spool. + + + +## worker logic + +- Each worker reads a configuration file containing the definition of + the tags it can manage. + +- Each tag is associated to a set of commands (URLs) and to a set of + keyrings. + +- A worker maintains a list of accepted scorsh tags, a map of + keyrings[tags], and a map of commands[tags]. + +When a new scorsh message is received by a worker, it looks through +the commit history for commits containing schorsh-tags. For each +scorsh-tag found, the worker looks if the tag is among the supported +ones, then checks if the commit can be verified by one of the keyrings +associated to the tag. If the set of keyrings for that tag is empty, +the tag is not allowed to run (this is a quick way to disable tags). + +(we might want to add an option to the definition of a scorsh-tag, +which allows to run the commands from unsigned and/or unverified +commits. This would be very dangerous though.) + +Then, if the tag is allowed to run, the worker executes each of the +commands in the tag definition, replacing arguments as needed. If a +command is a script (file://...), then it must also correspon to the +hash specified in the config, otherwise it will not be executed. + +When the worker is finished with all the commands for all the commits, +it will notify the master. diff --git a/scorsh.go b/scorsh.go index 08fc962..07745b3 100644 --- a/scorsh.go +++ b/scorsh.go @@ -14,11 +14,6 @@ const ( SCORSH_ERR_SIGNATURE ) -type SCORSHconf struct { - spool string -} - - type SCORSHmsg struct { repo string @@ -60,8 +55,12 @@ func main() { flag.Parse() - cfg := ReadConfig(*conf_file) + cfg := ReadGlobalConfig(*conf_file) + msg, status := StartWorkers(cfg) + + + log.Printf("%s\n", cfg) } diff --git a/worker_config.cfg b/worker_config.cfg new file mode 100644 index 0000000..5173b6f --- /dev/null +++ b/worker_config.cfg @@ -0,0 +1,37 @@ +# +# This is the typical worker configuration file. The file should be +# called "worker_config.cfg", and will be placed inside the worker +# directory. It defines the tags understood by the worker, with the +# corresponding list of commands +# +# + + +--- +w_tags: + [ + { + t_name: "BUILD", + t_keyrings: ["build_keyring.asc", "general_keyring.asc"], + t_commands: [ + { + c_url: "file:///home/user/bin/script.sh $1 $2", + c_hash: "12da324fb76s924acbce" + }, + { + c_url: "http://my.server.net/call.pl?branch=$1" + } + ] + }, + { + t_name: "PUBLISH", + t_keyrings: ["web_developers.asc"], + t_commands: [ + { + c_url: "file:///usr/local/bin/publish.py $repo $branch", + c_hash: "3234567898765432345678" + } + ] + } + ] +... \ No newline at end of file -- cgit v1.2.3