Adding Initial action #1
@ -78,6 +78,13 @@ func (pr *ProcessRepos) Process(ctx context.Context, repositoryUrls []string) er
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = pr.git.CreateBranch(ctx, repo)
|
||||||
|
if err != nil {
|
||||||
|
pr.logger.Error("could not create branch", zap.Error(err))
|
||||||
|
errChan <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = pr.action.Run(
|
err = pr.action.Run(
|
||||||
ctx,
|
ctx,
|
||||||
area,
|
area,
|
||||||
@ -116,13 +123,19 @@ func (pr *ProcessRepos) Process(ctx context.Context, repositoryUrls []string) er
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}, false)
|
}, false)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pr.logger.Error("could not run action", zap.Error(err))
|
pr.logger.Error("could not run action", zap.Error(err))
|
||||||
errChan <- err
|
errChan <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = pr.git.Push(ctx, repo)
|
||||||
|
if err != nil {
|
||||||
|
pr.logger.Error("could not push to repo", zap.Error(err))
|
||||||
|
errChan <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
pr.logger.Debug("processing done", zap.String("path", area.Path), zap.String("repoUrl", repoUrl))
|
pr.logger.Debug("processing done", zap.String("path", area.Path), zap.String("repoUrl", repoUrl))
|
||||||
}(ctx, repoUrl)
|
}(ctx, repoUrl)
|
||||||
}
|
}
|
||||||
|
@ -38,8 +38,9 @@ func NewServerDeps(logger *zap.Logger) *ServerDeps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openPGPConfig := &signer.OpenPgpConfig{
|
openPGPConfig := &signer.OpenPgpConfig{
|
||||||
PrivateKeyFilePath: "./examples/private.pgp",
|
PrivateKeyFilePath: "./example/testkey.private.pgp",
|
||||||
PrivateKeyPassword: "somepassword",
|
PrivateKeyPassword: "somepassword",
|
||||||
|
PrivateKeyIdentity: "kraken@kasperhermansen.com",
|
||||||
}
|
}
|
||||||
deps.openPGP = signer.NewOpenPGP(logger.With(zap.Namespace("openpgp")), openPGPConfig)
|
deps.openPGP = signer.NewOpenPGP(logger.With(zap.Namespace("openpgp")), openPGPConfig)
|
||||||
|
|
||||||
@ -51,7 +52,7 @@ func (deps *ServerDeps) GetStorageService() *storage.Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (deps *ServerDeps) GetGitProvider() *providers.Git {
|
func (deps *ServerDeps) GetGitProvider() *providers.Git {
|
||||||
return providers.NewGit(deps.logger.With(zap.Namespace("gitProvider")), deps.gitCfg)
|
return providers.NewGit(deps.logger.With(zap.Namespace("gitProvider")), deps.gitCfg, deps.openPGP)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (deps *ServerDeps) GetAction() *actions.Action {
|
func (deps *ServerDeps) GetAction() *actions.Action {
|
||||||
|
@ -2,11 +2,14 @@ package providers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.front.kjuulh.io/kjuulh/kraken/internal/services/signer"
|
||||||
"git.front.kjuulh.io/kjuulh/kraken/internal/services/storage"
|
"git.front.kjuulh.io/kjuulh/kraken/internal/services/storage"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp"
|
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
|
"github.com/go-git/go-git/v5/config"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
"github.com/go-git/go-git/v5/plumbing/object"
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
"github.com/go-git/go-git/v5/plumbing/transport"
|
"github.com/go-git/go-git/v5/plumbing/transport"
|
||||||
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||||
@ -20,6 +23,7 @@ import (
|
|||||||
type Git struct {
|
type Git struct {
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
gitConfig *GitConfig
|
gitConfig *GitConfig
|
||||||
|
openPGP *signer.OpenPGP
|
||||||
}
|
}
|
||||||
|
|
||||||
type GitRepo struct {
|
type GitRepo struct {
|
||||||
@ -45,8 +49,8 @@ type GitConfig struct {
|
|||||||
SshPrivateKeyPassword string
|
SshPrivateKeyPassword string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGit(logger *zap.Logger, gitConfig *GitConfig) *Git {
|
func NewGit(logger *zap.Logger, gitConfig *GitConfig, openPGP *signer.OpenPGP) *Git {
|
||||||
return &Git{logger: logger, gitConfig: gitConfig}
|
return &Git{logger: logger, gitConfig: gitConfig, openPGP: openPGP}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Git) Clone(ctx context.Context, storageArea *storage.Area, repoUrl string) (*GitRepo, error) {
|
func (g *Git) Clone(ctx context.Context, storageArea *storage.Area, repoUrl string) (*GitRepo, error) {
|
||||||
@ -70,13 +74,10 @@ func (g *Git) Clone(ctx context.Context, storageArea *storage.Area, repoUrl stri
|
|||||||
NoCheckout: false,
|
NoCheckout: false,
|
||||||
Depth: 1,
|
Depth: 1,
|
||||||
RecurseSubmodules: 1,
|
RecurseSubmodules: 1,
|
||||||
Progress: &zapio.Writer{
|
Progress: g.getProgressWriter(),
|
||||||
Log: g.logger.With(zap.String("process", "go-git")),
|
Tags: 0,
|
||||||
Level: zap.DebugLevel,
|
InsecureSkipTLS: false,
|
||||||
},
|
CABundle: []byte{},
|
||||||
Tags: 0,
|
|
||||||
InsecureSkipTLS: false,
|
|
||||||
CABundle: []byte{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := git.PlainCloneContext(ctx, storageArea.Path, false, &cloneOptions)
|
repo, err := git.PlainCloneContext(ctx, storageArea.Path, false, &cloneOptions)
|
||||||
@ -89,6 +90,13 @@ func (g *Git) Clone(ctx context.Context, storageArea *storage.Area, repoUrl stri
|
|||||||
return &GitRepo{repo: repo}, nil
|
return &GitRepo{repo: repo}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Git) getProgressWriter() *zapio.Writer {
|
||||||
|
return &zapio.Writer{
|
||||||
|
Log: g.logger.With(zap.String("process", "go-git")),
|
||||||
|
Level: zap.DebugLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Git) Add(ctx context.Context, storageArea *storage.Area, gitRepo *GitRepo) (*git.Worktree, error) {
|
func (g *Git) Add(ctx context.Context, storageArea *storage.Area, gitRepo *GitRepo) (*git.Worktree, error) {
|
||||||
worktree, err := gitRepo.repo.Worktree()
|
worktree, err := gitRepo.repo.Worktree()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -107,11 +115,71 @@ func (g *Git) Add(ctx context.Context, storageArea *storage.Area, gitRepo *GitRe
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
g.logger.Info("git status", zap.String("status", status.String()))
|
g.logger.Debug("git status", zap.String("status", status.String()))
|
||||||
|
|
||||||
return worktree, nil
|
return worktree, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Git) CreateBranch(ctx context.Context, gitRepo *GitRepo) error {
|
||||||
|
worktree, err := gitRepo.repo.Worktree()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
refSpec := plumbing.NewBranchReferenceName("kraken-apply")
|
||||||
|
err = gitRepo.repo.CreateBranch(&config.Branch{
|
||||||
|
Name: "kraken-apply",
|
||||||
|
Remote: "origin",
|
||||||
|
Merge: refSpec,
|
||||||
|
Rebase: "",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not create branch: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = worktree.Checkout(&git.CheckoutOptions{
|
||||||
|
Branch: plumbing.ReferenceName(refSpec.String()),
|
||||||
|
Create: true,
|
||||||
|
Force: false,
|
||||||
|
Keep: false,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not checkout branch: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteRef := plumbing.NewRemoteReferenceName("origin", "kraken-apply")
|
||||||
|
ref := plumbing.NewSymbolicReference(refSpec, remoteRef)
|
||||||
|
err = gitRepo.repo.Storer.SetReference(ref)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not set reference: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
auth, err := g.GetAuth()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = worktree.PullContext(ctx, &git.PullOptions{
|
||||||
|
RemoteName: "origin",
|
||||||
|
ReferenceName: "refs/heads/main",
|
||||||
|
SingleBranch: true,
|
||||||
|
Depth: 1,
|
||||||
|
Auth: auth,
|
||||||
|
RecurseSubmodules: 1,
|
||||||
|
Progress: g.getProgressWriter(),
|
||||||
|
Force: true,
|
||||||
|
InsecureSkipTLS: false,
|
||||||
|
CABundle: []byte{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not pull from origin: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
g.logger.Debug("done creating branches")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Git) Commit(ctx context.Context, gitRepo *GitRepo) error {
|
func (g *Git) Commit(ctx context.Context, gitRepo *GitRepo) error {
|
||||||
worktree, err := gitRepo.repo.Worktree()
|
worktree, err := gitRepo.repo.Worktree()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -122,12 +190,41 @@ func (g *Git) Commit(ctx context.Context, gitRepo *GitRepo) error {
|
|||||||
All: true,
|
All: true,
|
||||||
Author: &object.Signature{Name: "kraken", Email: "kraken@kasperhermansen.com", When: time.Now()},
|
Author: &object.Signature{Name: "kraken", Email: "kraken@kasperhermansen.com", When: time.Now()},
|
||||||
Committer: &object.Signature{Name: "kraken", Email: "kraken@kasperhermansen.com", When: time.Now()},
|
Committer: &object.Signature{Name: "kraken", Email: "kraken@kasperhermansen.com", When: time.Now()},
|
||||||
SignKey: &openpgp.Entity{},
|
SignKey: g.openPGP.SigningKey,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g.logger.Debug("done commiting objects")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Git) Push(ctx context.Context, gitRepo *GitRepo) error {
|
||||||
|
auth, err := g.GetAuth()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gitRepo.repo.PushContext(ctx, &git.PushOptions{
|
||||||
|
RemoteName: "origin",
|
||||||
|
RefSpecs: []config.RefSpec{},
|
||||||
|
Auth: auth,
|
||||||
|
Progress: g.getProgressWriter(),
|
||||||
|
Prune: false,
|
||||||
|
Force: false,
|
||||||
|
InsecureSkipTLS: false,
|
||||||
|
CABundle: []byte{},
|
||||||
|
RequireRemoteRefs: []config.RefSpec{},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
g.logger.Debug("done pushing branch")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,22 +2,25 @@ package signer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.front.kjuulh.io/kjuulh/curre"
|
"git.front.kjuulh.io/kjuulh/curre"
|
||||||
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
"github.com/ProtonMail/go-crypto/openpgp"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OpenPGP struct {
|
type OpenPGP struct {
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
PrivateKeyRing *crypto.KeyRing
|
SigningKey *openpgp.Entity
|
||||||
config *OpenPgpConfig
|
config *OpenPgpConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpenPgpConfig struct {
|
type OpenPgpConfig struct {
|
||||||
PrivateKeyFilePath string
|
PrivateKeyFilePath string
|
||||||
PrivateKeyPassword string
|
PrivateKeyPassword string
|
||||||
|
PrivateKeyIdentity string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOpenPGP(logger *zap.Logger, config *OpenPgpConfig) *OpenPGP {
|
func NewOpenPGP(logger *zap.Logger, config *OpenPgpConfig) *OpenPGP {
|
||||||
@ -29,26 +32,14 @@ func NewOpenPGP(logger *zap.Logger, config *OpenPgpConfig) *OpenPGP {
|
|||||||
|
|
||||||
func NewOpenPGPApp(openPGP *OpenPGP) curre.Component {
|
func NewOpenPGPApp(openPGP *OpenPGP) curre.Component {
|
||||||
return curre.NewFunctionalComponent(&curre.FunctionalComponent{
|
return curre.NewFunctionalComponent(&curre.FunctionalComponent{
|
||||||
InitFunc: func(fc *curre.FunctionalComponent, ctx context.Context) error {
|
InitFunc: func(_ *curre.FunctionalComponent, ctx context.Context) error {
|
||||||
|
keyring, err := buildKeyring(ctx, openPGP)
|
||||||
content, err := os.ReadFile(openPGP.config.PrivateKeyFilePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
privateKeyObj, err := crypto.NewKeyFromArmored(string(content))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
unlockedPrivateKeyRing, err := privateKeyObj.Unlock([]byte(openPGP.config.PrivateKeyPassword))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
privateKeyRing, err := crypto.NewKeyRing(unlockedPrivateKeyRing)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
openPGP.logger.Panic("could not build keyring", zap.Error(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
openPGP.PrivateKeyRing = privateKeyRing
|
openPGP.SigningKey = keyring
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
@ -59,5 +50,32 @@ func NewOpenPGPApp(openPGP *OpenPGP) curre.Component {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildKeyring(_ context.Context, openPGP *OpenPGP) (*openpgp.Entity, error) {
|
||||||
|
content, err := os.ReadFile(openPGP.config.PrivateKeyFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
reader := strings.NewReader(string(content))
|
||||||
|
|
||||||
|
es, err := openpgp.ReadArmoredKeyRing(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range es {
|
||||||
|
for k := range key.Identities {
|
||||||
|
if strings.Contains(k, openPGP.config.PrivateKeyIdentity) {
|
||||||
|
err = key.PrivateKey.Decrypt([]byte(openPGP.config.PrivateKeyPassword))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("could not find key matching identity")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user