diff options
| -rw-r--r-- | commits.go | 101 | ||||
| -rw-r--r-- | config.go | 2 | ||||
| -rw-r--r-- | notes.txt | 54 | ||||
| -rw-r--r-- | scorsh.go | 11 | ||||
| -rw-r--r-- | worker_config.cfg | 37 | 
5 files changed, 198 insertions, 7 deletions
| 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 +} @@ -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. @@ -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 | 
