@ -19,16 +19,15 @@ import (
yaml "gopkg.in/yaml.v2"
)
// TrunkCommit describes the structure of the object encoded into the git
// message of a commit in the repo trunk.
type TrunkCommit struct {
// ChangeCommit describes the structure of a change commit message.
type ChangeCommit struct {
Message string ` yaml:"message" `
ChangeHash yamlutil . Blob ` yaml:"change_hash" `
Credentials [ ] sigcred . Credential ` yaml:"credentials" `
}
type t cYAML struct {
Val Trunk Commit ` yaml:",inline" `
type c cYAML struct {
Val Change Commit ` yaml:",inline" `
}
func msgHead ( msg string ) string {
@ -40,34 +39,34 @@ func msgHead(msg string) string {
}
// MarshalText implements the encoding.TextMarshaler interface by returning the
// form the Trunk Commit object takes in the git commit message.
func ( tc Trunk Commit) MarshalText ( ) ( [ ] byte , error ) {
trunk CommitEncoded, err := yaml . Marshal ( tcYAML { t c} )
// form the Change Commit object takes in the git commit message.
func ( cc Change Commit) MarshalText ( ) ( [ ] byte , error ) {
change CommitEncoded, err := yaml . Marshal ( ccYAML { c c} )
if err != nil {
return nil , fmt . Errorf ( "failed to encode Trunk Commit message: %w" , err )
return nil , fmt . Errorf ( "failed to encode Change Commit message: %w" , err )
}
fullMsg := msgHead ( t c. Message ) + "\n\n" + string ( trunk CommitEncoded)
fullMsg := msgHead ( c c. Message ) + "\n\n" + string ( change CommitEncoded)
return [ ] byte ( fullMsg ) , nil
}
// UnmarshalText implements the encoding.TextUnmarshaler interface by decoding a
// Trunk Commit object which has been encoded into a git commit message.
func ( tc * Trunk Commit) UnmarshalText ( msg [ ] byte ) error {
// Change Commit object which has been encoded into a git commit message.
func ( cc * Change Commit) UnmarshalText ( msg [ ] byte ) error {
i := bytes . Index ( msg , [ ] byte ( "\n" ) )
if i < 0 {
return fmt . Errorf ( "commit message %q is malformed" , msg )
}
msgHead , msg := msg [ : i ] , msg [ i : ]
var tcy t cYAML
if err := yaml . Unmarshal ( msg , & t cy) ; err != nil {
return fmt . Errorf ( "could not unmarshal Trunk Commit message: %w" , err )
var ccy c cYAML
if err := yaml . Unmarshal ( msg , & c cy) ; err != nil {
return fmt . Errorf ( "could not unmarshal Change Commit message: %w" , err )
}
* tc = t cy. Val
if ! strings . HasPrefix ( t c. Message , string ( msgHead ) ) {
return errors . New ( "encoded TrunkCommit is malformed, it might not be an encoded Trunk Commit" )
* cc = c cy. Val
if ! strings . HasPrefix ( c c. Message , string ( msgHead ) ) {
return errors . New ( "encoded ChangeCommit is malformed, it might not be an encoded Change Commit" )
}
return nil
@ -94,19 +93,19 @@ func (r *Repo) Commit(m encoding.TextMarshaler, accountID string) (plumbing.Hash
} )
}
// NewTrunkCommit constructs a TrunkCommit using the given SignifierInterface to
// create a Credential for it.
func ( r * Repo ) NewTrunk Commit ( msg , accountID string , sig sigcred . SignifierInterface ) ( Trunk Commit, error ) {
// NewChangeCommit constructs a ChangeCommit using the given SignifierInterface
// to create a Credential for it.
func ( r * Repo ) NewChange Commit ( msg , accountID string , sig sigcred . SignifierInterface ) ( Change Commit, error ) {
_ , headTree , err := r . head ( )
if errors . Is ( err , plumbing . ErrReferenceNotFound ) {
headTree = & object . Tree { }
} else if err != nil {
return Trunk Commit{ } , err
return Change Commit{ } , err
}
_ , stagedTree , err := fs . FromStagedChangesTree ( r . GitRepo )
if err != nil {
return Trunk Commit{ } , err
return Change Commit{ } , err
}
// this is necessarily different than headTree for the case of there being
@ -116,18 +115,18 @@ func (r *Repo) NewTrunkCommit(msg, accountID string, sig sigcred.SignifierInterf
// data might be).
sigFS , err := r . headOrRawFS ( )
if err != nil {
return Trunk Commit{ } , err
return Change Commit{ } , err
}
cfg , err := r . loadConfig ( sigFS )
if err != nil {
return Trunk Commit{ } , fmt . Errorf ( "could not load config: %w" , err )
return Change Commit{ } , fmt . Errorf ( "could not load config: %w" , err )
}
changeHash := genChangeHash ( nil , msg , headTree , stagedTree )
cred , err := sig . Sign ( sigFS , changeHash )
if err != nil {
return Trunk Commit{ } , fmt . Errorf ( "failed to sign commit hash: %w" , err )
return Change Commit{ } , fmt . Errorf ( "failed to sign commit hash: %w" , err )
}
cred . AccountID = accountID
@ -139,10 +138,10 @@ func (r *Repo) NewTrunkCommit(msg, accountID string, sig sigcred.SignifierInterf
headTree , stagedTree ,
)
if err != nil {
return Trunk Commit{ } , fmt . Errorf ( "commit would not satisfy access controls: %w" , err )
return Change Commit{ } , fmt . Errorf ( "commit would not satisfy access controls: %w" , err )
}
return Trunk Commit{
return Change Commit{
Message : msg ,
ChangeHash : changeHash ,
Credentials : [ ] sigcred . Credential { cred } ,
@ -181,9 +180,9 @@ func (r *Repo) assertAccessControls(
return nil
}
// VerifyTrunkCommit verifies that the commit at the given hash, which is
// presumably on the repo trunk, is gucci.
func ( r * Repo ) VerifyTrunk Commit ( h plumbing . Hash ) error {
// VerifyChangeCommit verifies that the change commit at the given hash, which
// is presumably on the repo trunk, is gucci.
func ( r * Repo ) VerifyChange Commit ( h plumbing . Hash ) error {
commit , err := r . GitRepo . CommitObject ( h )
if err != nil {
return fmt . Errorf ( "could not retrieve commit object: %w" , err )
@ -194,8 +193,8 @@ func (r *Repo) VerifyTrunkCommit(h plumbing.Hash) error {
return fmt . Errorf ( "could not retrieve tree object: %w" , err )
}
var trunkCommit Trunk Commit
if err := trunk Commit. UnmarshalText ( [ ] byte ( commit . Message ) ) ; err != nil {
var changeCommit Change Commit
if err := change Commit. UnmarshalText ( [ ] byte ( commit . Message ) ) ; err != nil {
return err
}
@ -218,21 +217,21 @@ func (r *Repo) VerifyTrunkCommit(h plumbing.Hash) error {
}
err = r . assertAccessControls (
cfg . AccessControls , trunk Commit. Credentials ,
cfg . AccessControls , change Commit. Credentials ,
parentTree , commitTree ,
)
if err != nil {
return fmt . Errorf ( "failed to satisfy all access controls: %w" , err )
}
expectedChangeHash := genChangeHash ( nil , trunk Commit. Message , parentTree , commitTree )
if ! bytes . Equal ( trunk Commit. ChangeHash , expectedChangeHash ) {
expectedChangeHash := genChangeHash ( nil , change Commit. Message , parentTree , commitTree )
if ! bytes . Equal ( change Commit. ChangeHash , expectedChangeHash ) {
return fmt . Errorf ( "malformed change_hash in commit body, is %s but should be %s" ,
base64 . StdEncoding . EncodeToString ( expectedChangeHash ) ,
base64 . StdEncoding . EncodeToString ( trunk Commit. ChangeHash ) )
base64 . StdEncoding . EncodeToString ( change Commit. ChangeHash ) )
}
for _ , cred := range trunk Commit. Credentials {
for _ , cred := range change Commit. Credentials {
sig , err := r . signifierForCredential ( sigFS , cred )
if err != nil {
return fmt . Errorf ( "error finding signifier for credential %+v: %w" , cred , err )