aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--cmd/main.go20
-rw-r--r--gitserver.yaml9
-rw-r--r--go.mod29
-rw-r--r--go.sum75
-rw-r--r--internal/admin/middleware.go15
-rw-r--r--internal/admin/model.go102
-rw-r--r--internal/admin/model_test.go164
-rw-r--r--internal/admin/service.go56
-rw-r--r--internal/admin/service_test.go132
-rw-r--r--internal/authz/middleware.go2
-rw-r--r--internal/authz/middleware_test.go15
-rw-r--r--policy.csv19
-rw-r--r--testpolicy.csv11
13 files changed, 512 insertions, 137 deletions
diff --git a/cmd/main.go b/cmd/main.go
index f2f1c63..bf3697d 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -12,14 +12,15 @@ import (
)
var (
- reposDir = flag.String("r", "./repos", "Directory containing git repositories")
- backendCommand = flag.String("c", "git http-backend", "CGI binary to execute")
- addr = flag.String("l", ":8080", "Address/port to listen on")
- modelPath = flag.String("m", "./auth_model.ini", "Authentication model")
- policyPath = flag.String("p", "./policy.csv", "auth policy")
- serverConfig = flag.String("s", "./gitserver.yaml", "serverconfig path")
- newToken = flag.Bool("t", false, "make a new token")
- updatePolicies = flag.Bool("u", false, "update policies")
+ reposDir = flag.String("r", "./repos", "Directory containing git repositories")
+ mgmtRepo = flag.Bool("a", true, "mgmt repo used for configuration")
+ backendCommand = flag.String("c", "git http-backend", "CGI binary to execute")
+ addr = flag.String("l", ":8080", "Address/port to listen on")
+ modelPath = flag.String("m", "./auth_model.ini", "Authentication model")
+ policyPath = flag.String("p", "./policy.csv", "auth policy")
+ serverConfigPath = flag.String("s", "/gitserver.yaml", "serverconfig path")
+ newToken = flag.Bool("t", false, "make a new token")
+ updatePolicies = flag.Bool("u", false, "update policies")
)
func main() {
@@ -32,7 +33,7 @@ func main() {
fmt.Printf("token: %s\nhash: %s\n", token, hash)
return
}
- adminSvc := admin.NewService(*modelPath, *policyPath, *serverConfig)
+ adminSvc := admin.NewService(*modelPath, *policyPath, *serverConfigPath, *reposDir, *mgmtRepo)
adminSvc.InitServer()
tokens := authz.NewTokenMap()
err := tokens.LoadTokensFromFile("./tokens.csv")
@@ -42,6 +43,7 @@ func main() {
router := http.NewServeMux()
// TODO we don't want to use a global
// de-reference args
+ router.Handle("/mgmt/", admin.AdminHooks(adminSvc, git.GitHttpBackendHandler(*reposDir, *backendCommand)))
router.Handle("/", git.GitHttpBackendHandler(*reposDir, *backendCommand))
mux := authz.Authentication(tokens, authz.Authorization(adminSvc, router))
log.Fatal(http.ListenAndServe(":8080", mux))
diff --git a/gitserver.yaml b/gitserver.yaml
index 1ffc59d..2a2c828 100644
--- a/gitserver.yaml
+++ b/gitserver.yaml
@@ -3,13 +3,18 @@ name: "go-git-server"
version: "v1alpha1"
basepath: ./repos
repos:
+ - name: mgmt
+ public: false
+ permissions:
+ - role: admin
+ mode: 1
- name: testmerepo
public: true
git_web_config:
owner: grumps
- description: |-
+ description: >-
A wrapper to git http-backend providing authentcation and authorization
- Inspired by gitolite
+ inspired by gitolite.
permissions:
- role: maintainers
mode: 1
diff --git a/go.mod b/go.mod
index 1bb8023..550cf94 100644
--- a/go.mod
+++ b/go.mod
@@ -2,32 +2,33 @@ module git.ofmax.li/go-git-server
go 1.19
-require golang.org/x/crypto v0.3.0
+require (
+ github.com/casbin/casbin/v2 v2.56.0
+ github.com/go-git/go-billy v4.2.0+incompatible
+ github.com/go-git/go-billy/v5 v5.4.1
+ github.com/go-git/go-git/v5 v5.6.1
+ golang.org/x/crypto v0.6.0
+ gopkg.in/ini.v1 v1.67.0
+ gopkg.in/yaml.v2 v2.4.0
+ sigs.k8s.io/yaml v1.3.0
+)
require (
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
- github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 // indirect
- github.com/acomagu/bufpipe v1.0.3 // indirect
- github.com/casbin/casbin v1.9.1 // indirect
- github.com/casbin/casbin/v2 v2.56.0 // indirect
+ github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
+ github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/cloudflare/circl v1.1.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
- github.com/go-git/go-billy/v5 v5.3.1 // indirect
- github.com/go-git/go-git/v5 v5.5.1 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
- github.com/pjbgf/sha1cd v0.2.3 // indirect
+ github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/skeema/knownhosts v1.1.0 // indirect
- github.com/subpop/go-ini v0.1.4 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
- golang.org/x/net v0.2.0 // indirect
- golang.org/x/sys v0.2.0 // indirect
- gopkg.in/ini.v1 v1.67.0 // indirect
+ golang.org/x/net v0.7.0 // indirect
+ golang.org/x/sys v0.5.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
- sigs.k8s.io/yaml v1.3.0 // indirect
)
diff --git a/go.sum b/go.sum
index 29ad4fd..63a5c10 100644
--- a/go.sum
+++ b/go.sum
@@ -2,34 +2,42 @@ github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
-github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 h1:ra2OtmuW0AE5csawV4YXMNGNQQXvLRps3z2Z59OPO+I=
-github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8=
-github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
-github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
+github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
+github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
+github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
+github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
+github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
-github.com/casbin/casbin v1.9.1 h1:ucjbS5zTrmSLtH4XogqOG920Poe6QatdXtz1FEbApeM=
-github.com/casbin/casbin v1.9.1/go.mod h1:z8uPsfBJGUsnkagrt3G8QvjgTKFMBJ32UP8HpZllfog=
github.com/casbin/casbin/v2 v2.56.0 h1:4qM+hDfj+i9M6lBbguafWKE/8tJA+9vRY5+l0ZB5WTo=
github.com/casbin/casbin/v2 v2.56.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY=
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
+github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
-github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
+github.com/go-git/go-billy v4.2.0+incompatible h1:Z6QtVXd5tjxUtcODLugkJg4WaZnGg13CD8qB9pr+7q0=
+github.com/go-git/go-billy v4.2.0+incompatible/go.mod h1:hedUGslB3n31bx5SW9KMjV/t0CUKnrapjVG9fT7xKX4=
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
+github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
+github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
+github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ=
github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
-github.com/go-git/go-git/v5 v5.5.1 h1:5vtv2TB5PM/gPM+EvsHJ16hJh4uAkdGcKilcwY7FYwo=
-github.com/go-git/go-git/v5 v5.5.1/go.mod h1:uz5PQ3d0gz7mSgzZhSJToM6ALPaKCdSnl58/Xb5hzr8=
+github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk=
+github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8=
+github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
@@ -39,15 +47,22 @@ github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
+github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/pjbgf/sha1cd v0.2.3 h1:uKQP/7QOzNtKYH7UTohZLcjF5/55EnTw0jO/Ru4jZwI=
-github.com/pjbgf/sha1cd v0.2.3/go.mod h1:HOK9QrgzdHpbc2Kzip0Q1yi3M2MFGPADtR6HjG65m5M=
+github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
+github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
@@ -57,33 +72,36 @@ github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXi
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/subpop/go-ini v0.1.4 h1:+OVDOLyoQQCkk36v48bDcBscw2GCn9cesQc6PFLYdg8=
-github.com/subpop/go-ini v0.1.4/go.mod h1:q0fhdlbGE3dI9dHPgUntXh1ggwR+SpfXL/kogOefaBE=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg=
-golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
-golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
+golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
+golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
-golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
-golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -97,25 +115,34 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
-golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@@ -126,6 +153,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
diff --git a/internal/admin/middleware.go b/internal/admin/middleware.go
new file mode 100644
index 0000000..56d4797
--- /dev/null
+++ b/internal/admin/middleware.go
@@ -0,0 +1,15 @@
+package admin
+
+import (
+ "log"
+ "net/http"
+)
+
+// Admin middleware to handle requests to the admin repo.
+func AdminHooks(adminSvc *Servicer, next http.Handler) http.Handler {
+ return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
+ log.Printf("stuffs about to reload %s", "now")
+ next.ServeHTTP(rw, req)
+ go adminSvc.Reload()
+ })
+}
diff --git a/internal/admin/model.go b/internal/admin/model.go
index cf69fcd..5a7f984 100644
--- a/internal/admin/model.go
+++ b/internal/admin/model.go
@@ -10,9 +10,11 @@ import (
"os"
"path/filepath"
+ "github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-billy/v5/osfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/storage/filesystem"
+ "github.com/go-git/go-git/v5/storage/memory"
"gopkg.in/ini.v1"
@@ -28,6 +30,8 @@ const (
Admin = 2
// GitExportMagic magic file name for daemon export
GitExportMagic = "git-daemon-export-ok"
+ // GitWebExportMagic
+ GitWebExportMagic = "git-web-export-ok"
)
// Action composite type for modes
@@ -67,22 +71,65 @@ type ServerRepos struct {
BasePath string `json:"basepath"`
}
-func loadServerConfig(configPath string) *ServerRepos {
- file, err := os.Open(configPath)
+func loadFromGit(gitUrl, filePath string) ([]byte, error) {
+ fs := memfs.New()
+ storer := memory.NewStorage()
+ _, err := git.Clone(storer, fs, &git.CloneOptions{
+ URL: gitUrl,
+ })
if err != nil {
- log.Fatalf("Failed to open gitserver config %s", err)
+ // log.error
+ fmt.Printf("coudln't clone mgmt repo %s", err)
+ return []byte(""), errors.New("coudln't clone mgmt repo")
+ }
+ file, err := fs.Open(filePath)
+ if err != nil {
+ fmt.Printf("Failed to open gitserver config %s", err)
+ return []byte(""), errors.New("coudln't open git config file from mgmt repo")
}
defer file.Close()
- b, err := io.ReadAll(file)
+ return io.ReadAll(file)
+}
+
+func loadLocalFile(path string) ([]byte, error) {
+ file, err := os.Open(path)
+ if err != nil {
+ log.Printf("config file not opened %s", path)
+ return []byte{}, err
+ }
+ configBytes, err := io.ReadAll(file)
if err != nil {
- log.Fatalf("Failed to read the gitserver config %s", err)
+ log.Print("config file not read")
+ return []byte{}, err
+ }
+ return configBytes, nil
+}
+
+func loadServerConfig(mgmtRepo bool, baseDir, configPath string) (*ServerRepos, error) {
+ configBytes := []byte{}
+ var err error
+ if mgmtRepo {
+ repoURI := filepath.Join("file:///", baseDir, "mgmt.git")
+ configBytes, err = loadFromGit(repoURI, configPath)
+ if err != nil {
+ // log.error
+ log.Print("Failed to load config file from git")
+ return &ServerRepos{}, err
+ }
+ } else {
+ configBytes, err = loadLocalFile(filepath.Join(baseDir, configPath))
+ if err != nil {
+ // log.error
+ log.Print("Failed to load config file from git")
+ return &ServerRepos{}, err
+ }
}
config := &ServerRepos{}
- err = yaml.Unmarshal(b, &config)
+ err = yaml.Unmarshal(configBytes, &config)
if err != nil {
- log.Fatalf("Failed to parse gitserver config %s", err)
+ return &ServerRepos{}, errors.New("Could not parse gitserver config")
}
- return config
+ return config, nil
}
// ServerPolicies generate casbin policies
@@ -108,19 +155,20 @@ func readOnlyPaths(role, repoName string) [][]string {
}
}
func writePaths(role, repoName string) [][]string {
- return [][]string{[]string{role, fmt.Sprintf("/%s/git-recieve-pack", repoName), "POST"}}
+ return [][]string{[]string{role, fmt.Sprintf("/%s/git-receive-pack", repoName), "POST"}}
}
// Policy generate policy for repo base on mode
func (p *Permission) Policy(repoName string) [][]string {
policies := [][]string{}
// if read mode or greater e.g. write mode
+ roleName := fmt.Sprintf("role:%s", p.Role)
if p.Mode >= Read {
- policies = append(policies, readOnlyPaths(p.Role, repoName)...)
+ policies = append(policies, readOnlyPaths(roleName, repoName)...)
}
// if write mode
if p.Mode >= Write {
- policies = append(policies, writePaths(p.Role, repoName)...)
+ policies = append(policies, writePaths(roleName, repoName)...)
}
return policies
}
@@ -145,8 +193,18 @@ func (r *GitRepo) ReconcileRepo(basePath string) {
strg := filesystem.NewStorage(fs, nil)
_, _ = git.Init(strg, nil)
}
+ // set export file for git-http-backend
+ okExport := filepath.Join(repoBase, GitExportMagic)
+ _, err = os.Stat(okExport)
+ if errors.Is(err, fs.ErrNotExist) {
+ // Create web export
+ f, err := os.Create(okExport)
+ f.Close()
+ if err != nil {
+ log.Fatalf("%s coudln't be created %s", GitExportMagic, err)
+ }
+ }
r.ConfigureExport(repoBase)
-
if r.GitWebConfig == nil {
r.GitWebConfig = &GitWeb{}
}
@@ -155,24 +213,10 @@ func (r *GitRepo) ReconcileRepo(basePath string) {
// ConfigureExport setup repo for sharing and configure web settings
func (r *GitRepo) ConfigureExport(repoBase string) {
- // do nothing on public repos
- okExport := filepath.Join(repoBase, GitExportMagic)
- _, err := os.Stat(okExport)
- // Not public but the export setting is setting exists
- if !r.Public && err == nil {
- // delete file
- os.Remove(okExport)
- return
- }
- // Not public and the file doesn't exist
- if !r.Public && errors.Is(err, fs.ErrNotExist) {
- return
- }
- //
- f, err := os.Create(okExport)
- defer f.Close()
+ okExport := filepath.Join(repoBase, GitWebExportMagic)
+ _, err := os.Create(okExport)
if err != nil {
- log.Fatalf("git-daemon-export-ok coudln't be created %s", err)
+ log.Fatalf("%s coudln't be created %s", GitWebExportMagic, err)
}
}
diff --git a/internal/admin/model_test.go b/internal/admin/model_test.go
index 79e3cb5..7f816f5 100644
--- a/internal/admin/model_test.go
+++ b/internal/admin/model_test.go
@@ -1,8 +1,10 @@
package admin
import (
+ "bytes"
"errors"
"fmt"
+ "io"
"io/fs"
"io/ioutil"
"os"
@@ -10,18 +12,21 @@ import (
"strings"
"testing"
+ "github.com/go-git/go-billy/v5/osfs"
+ "github.com/go-git/go-git/v5"
+ "github.com/go-git/go-git/v5/storage/filesystem"
"gopkg.in/ini.v1"
)
func TestCasbinPolicies(t *testing.T) {
- roleName := "mr:role"
+ roleName := "myrole"
repoName := "myrepo"
pRO := &Permission{
Role: roleName,
Mode: 0,
}
pW := &Permission{
- Role: "my:admin",
+ Role: "admin",
Mode: 1,
}
@@ -50,7 +55,7 @@ func TestCasbinPolicies(t *testing.T) {
if wPolicies[0][0] != roleName {
t.Fatal("Role name doesn't match")
}
- if wPolicies[0][1] != fmt.Sprintf("/%s/git-recieve-pack", repoName) {
+ if wPolicies[0][1] != fmt.Sprintf("/%s/git-receive-pack", repoName) {
t.Fatal("Policy missing write path")
}
})
@@ -76,6 +81,128 @@ func TestCasbinPolicies(t *testing.T) {
})
}
+func TestLoadServerConfig(t *testing.T) {
+ t.Run("testing server config from file", func(t *testing.T) {
+ localDir := t.TempDir()
+ // TODO Refactor next touch
+ localFile := filepath.Join(localDir, "stuff.yaml")
+ srcFile, err := os.Open("../../gitserver.yaml")
+ if err != nil {
+ t.Fatalf("Error opening base config %s", err)
+ }
+ defer srcFile.Close()
+
+ // dest
+ destFile, err := os.OpenFile(localFile, os.O_RDWR|os.O_CREATE, 0755)
+ if err != nil {
+ t.Fatalf("failed to open destination in git repo %s", err)
+ }
+ defer destFile.Close()
+
+ // copy
+ if _, err := io.Copy(destFile, srcFile); err != nil {
+ t.Fatalf("Error copying file %s", err)
+ }
+
+ // end copy file
+ loadedFile, err := loadServerConfig(false, localDir, "stuff.yaml")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(loadedFile.Repos) != 2 {
+ t.Fatalf("expected to find 2 repos found %d", len(loadedFile.Repos))
+ }
+ })
+
+ t.Run("testing server config from git", func(t *testing.T) {
+
+ })
+}
+
+func TestLocalFile(t *testing.T) {
+ localDir := t.TempDir()
+ localFile := filepath.Join(localDir, "stuff.yaml")
+ os.WriteFile(localFile, []byte("stuff"), 0750)
+ loadedFile, err := loadLocalFile(localFile)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !bytes.Contains(loadedFile, []byte("stuff")) {
+ t.Fatal("failed to find expected contents in localfile")
+ }
+ _, err = loadLocalFile("dne.txt")
+ if err == nil {
+ t.Fatal("Expected to find and error and didn't")
+ }
+}
+
+func TestMgmtGitConfig(t *testing.T) {
+ // setup tempdir
+ gitDir := t.TempDir()
+ // init git repo
+ gitFs := osfs.New(gitDir)
+ strg := filesystem.NewStorage(gitFs, nil)
+ repo, _ := git.Init(strg, gitFs)
+ // add file
+
+ // src
+ srcFile, err := os.Open("../../gitserver.yaml")
+ if err != nil {
+ t.Fatalf("Error opening base config %s", err)
+ }
+ defer srcFile.Close()
+
+ // file name
+ // fileToCommit := fs.Join(gitDir, "gitserver.yaml")
+ fileToCommit := "gitserver.yaml"
+
+ // dest
+ destFile, err := gitFs.OpenFile(fileToCommit, os.O_RDWR|os.O_CREATE, 0755)
+ if err != nil {
+ t.Fatalf("failed to open destination in git repo %s", err)
+ }
+ defer destFile.Close()
+
+ // copy
+ if _, err := io.Copy(destFile, srcFile); err != nil {
+ t.Fatalf("Error copying file %s", err)
+ }
+ // commit
+ wt, err := repo.Worktree()
+ if err != nil {
+ t.Fatal(err)
+ }
+ wt.Add(fileToCommit)
+ _, err = wt.Commit(fileToCommit, &git.CommitOptions{})
+ if err != nil {
+ t.Fatalf("Error creating commit %s", err)
+ }
+
+ // run load func
+ content, err := loadFromGit(gitDir, "gitserver.yaml")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // "go-git-server"
+ if !bytes.Contains(content, []byte("go-git-server")) {
+ t.Fatal("config missing expected")
+ }
+
+ // check couldnt clone err
+ _, err = loadFromGit("/dne/bar", "gitserver.yaml")
+ if err == nil {
+ t.Fatal("expected an cloning repo didn't find one")
+ }
+ // check couldnt open file err
+ _, err = loadFromGit(gitDir, "dne.yaml")
+ if err == nil {
+ t.Fatal("expected an error opening config file didn't find one")
+ }
+ // TODO run via serverLoadConfig
+}
+
func TestConfigReconcile(t *testing.T) {
tempDir := t.TempDir()
defer os.RemoveAll(tempDir)
@@ -89,8 +216,7 @@ func TestConfigReconcile(t *testing.T) {
}
f.Close()
repo := &GitRepo{
- Public: true,
- Name: "testrepo",
+ Name: "testrepo",
}
t.Run("test add gitweb section and remove it", func(t *testing.T) {
// make "fake" repo
@@ -126,7 +252,7 @@ func TestConfigReconcile(t *testing.T) {
}
})
t.Run("test magic export file is created", func(t *testing.T) {
- exportPath := filepath.Join(testRepo, GitExportMagic)
+ exportPath := filepath.Join(testRepo, GitWebExportMagic)
repo.ConfigureExport(testRepo)
_, err := os.Stat(exportPath)
if errors.Is(err, fs.ErrNotExist) {
@@ -135,13 +261,6 @@ func TestConfigReconcile(t *testing.T) {
if err != nil {
t.Fatalf("encountered an error %s", err)
}
- // copy repo
- pvtRepo := repo
- pvtRepo.Public = false
- pvtRepo.ConfigureExport(testRepo)
- if _, err := os.Stat(exportPath); err == nil {
- t.Fatal("expected export file exist, but does not exist")
- }
})
}
@@ -150,8 +269,7 @@ func TestRepoReconcile(t *testing.T) {
print(tempDir)
// defer os.RemoveAll(tempDir)
repo := &GitRepo{
- Public: true,
- Name: "testrepo",
+ Name: "TestMeRepo",
GitWebConfig: &GitWeb{
"owner",
"description",
@@ -181,23 +299,9 @@ bare = true
if !strings.Contains(string(content), "description") {
t.Fatal("expected to find 'description' in config, didn't found", string(content))
}
- gitExportMagicPath := filepath.Join(tempDir, fmt.Sprintf("%s.git", repo.Name), GitExportMagic)
+ gitExportMagicPath := filepath.Join(tempDir, fmt.Sprintf("%s.git", repo.Name), GitWebExportMagic)
if _, err := os.Stat(gitExportMagicPath); errors.Is(err, fs.ErrNotExist) {
t.Fatal("expected git export magic to be created, but does not exist")
}
- // Test that repo is switched back to private
- repo.Public = false
- // re-write the base config to repo
- ioutil.WriteFile(tempConfigFile, defaultFile, 0644)
- // re-reconcile
- repo.ReconcileRepo(tempDir)
- // check if description is *NOT* in the file
- if !strings.Contains(string(content), "description") {
- t.Fatal("expected to *NOT* find 'description' in config, didn't found", string(content))
- }
- // make sure export is removed
- if _, err := os.Stat(gitExportMagicPath); !errors.Is(err, fs.ErrNotExist) {
- t.Fatal("expected git export magic to not exist, but *does* exist")
- }
}
diff --git a/internal/admin/service.go b/internal/admin/service.go
index 80056b7..84547fa 100644
--- a/internal/admin/service.go
+++ b/internal/admin/service.go
@@ -9,28 +9,72 @@ import (
// Servicer container for dependencies and functions
type Servicer struct {
*casbin.SyncedEnforcer
- Conf *ServerRepos
+ Conf *ServerRepos
+ serverConfigPath string
+ reposDir string
+ mgmtRepo bool
+}
+
+// Reload reoload server config and sync policies
+func (s *Servicer) Reload() {
+ tmpConfig, err := loadServerConfig(s.mgmtRepo, s.reposDir, s.serverConfigPath)
+ if err != nil {
+ // log.error
+ log.Printf("failed to load config %s", err)
+ log.Print("refusing to reload config")
+ return
+ }
+ s.Conf = tmpConfig
+ s.InitServer()
}
// InitServer initialize a git server and configure
func (s *Servicer) InitServer() {
policies := s.Conf.ServerPolicies()
- s.AddPolicies(policies)
- s.SavePolicy()
- s.LoadPolicy()
+ log.Print("policies generated")
+ numAdded := 0
+ for _, policy := range policies {
+ added, err := s.AddPolicy(policy[0], policy[1], policy[2])
+ if err != nil {
+ // log.error
+ log.Printf("error adding policy %s %s %s error %s", policy[0], policy[1], policy[2], err)
+ continue
+ }
+ if added {
+ numAdded += 1
+ }
+ }
+ log.Printf("policies added %d", numAdded)
+ if err := s.SavePolicy(); err != nil {
+ log.Print("couldn't save policy")
+ }
+ log.Printf("policies saved")
+ if err := s.LoadPolicy(); err != nil {
+ log.Print("cloudn't load policy")
+ }
+ log.Print("policies loaded")
s.Conf.ConfigureRepos()
+ log.Print("configured repos")
}
// NewService create a new admin service, load config, and generate policies
-func NewService(modelPath, policyPath, serverConfigPath string) *Servicer {
+func NewService(modelPath, policyPath, serverConfigPath, reposDir string, mgmtRepo bool) *Servicer {
enf, err := casbin.NewSyncedEnforcer(modelPath, policyPath)
if err != nil {
log.Fatalf("Couldn't load the enforcer encountered the following error: %s", err)
}
- conf := loadServerConfig(serverConfigPath)
+
+ conf, err := loadServerConfig(mgmtRepo, reposDir, serverConfigPath)
+ if err != nil {
+ // log.error
+ log.Fatalf("Coudln't load server config %s", err)
+ }
svc := &Servicer{
enf,
conf,
+ serverConfigPath,
+ reposDir,
+ mgmtRepo,
}
svc.InitServer()
return svc
diff --git a/internal/admin/service_test.go b/internal/admin/service_test.go
new file mode 100644
index 0000000..fdd3aa6
--- /dev/null
+++ b/internal/admin/service_test.go
@@ -0,0 +1,132 @@
+package admin
+
+import (
+ "io"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+var (
+ updatedServerConfig []byte = []byte(`
+---
+name: "go-git-server"
+version: "v1alpha1"
+basepath: ./repos
+repos:
+ - name: mgmt
+ permissions:
+ - role: admin
+ mode: 1
+ - name: testmerepo
+ git_web_config:
+ owner: grumps
+ description: >-
+ A wrapper to git http-backend providing authentcation and authorization
+ inspired by gitolite.
+ permissions:
+ - role: maintainers
+ mode: 1
+ - name: thisismynewrepo
+ git_web_config:
+ owner: grumps
+ description: >-
+ A wrapper to git http-backend providing authentcation and authorization
+ inspired by gitolite.
+ permissions:
+ - role: maintainers
+ mode: 1
+`)
+)
+
+func copyFile(t *testing.T, srcFilePath, destPath string) {
+
+ srcFile, err := os.Open(srcFilePath)
+ if err != nil {
+ t.Fatalf("Error opening base config %s", err)
+ }
+ defer srcFile.Close()
+
+ // dest
+ destFile, err := os.OpenFile(destPath, os.O_RDWR|os.O_CREATE, 0755)
+ if err != nil {
+ t.Fatalf("failed to open destination in git repo %s", err)
+ }
+ defer destFile.Close()
+
+ // copy
+ if _, err := io.Copy(destFile, srcFile); err != nil {
+ t.Fatalf("Error copying file %s", err)
+ }
+}
+
+func TestInitServer(t *testing.T) {
+ tempDir := t.TempDir()
+ tempRepoDir := t.TempDir()
+
+ // auth model
+ destModelFile := filepath.Join(tempDir, "auth_model.ini")
+ srcModelFile := "../../auth_model.ini"
+ copyFile(t, srcModelFile, destModelFile)
+ // end auth model
+
+ // policy
+ destPolicyFile := filepath.Join(tempDir, "testpolicy.csv")
+ srcPolicyFile := "../../testpolicy.csv"
+ copyFile(t, srcPolicyFile, destPolicyFile)
+ // end policy
+
+ // config
+ destConfigFile := filepath.Join(tempRepoDir, "gitserver.yaml")
+ srcConfigFile := "../../gitserver.yaml"
+ copyFile(t, srcConfigFile, destConfigFile)
+ // end config
+
+ t.Run("test reload config success", func(t *testing.T) {
+ svc := NewService(destModelFile,
+ destPolicyFile,
+ "gitserver.yaml",
+ tempRepoDir,
+ false)
+ err := os.WriteFile(destConfigFile, updatedServerConfig, 0755)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // stuff
+ svc.Reload()
+ // check policy file to make sure it was saved
+ data, err := os.ReadFile(destPolicyFile)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !strings.Contains(string(data), "thisismynewrepo") {
+ t.Fatal("expected to find test new repo but didn't")
+ }
+
+ })
+ t.Run("test reload config err", func(t *testing.T) {
+ svc := NewService(destModelFile,
+ destPolicyFile,
+ "gitserver.yaml",
+ tempRepoDir,
+ false)
+ notAGoodConfig := []byte("this is not valid yaml")
+ err := os.WriteFile(destConfigFile, notAGoodConfig, 0755)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // stuff
+ svc.Reload()
+ // check policy file to make sure it wasn't saved
+ data, err := os.ReadFile(destPolicyFile)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if !strings.Contains(string(data), "mgmt") {
+ log.Fatal("expected to mgmt repo but didn't in policy")
+ }
+
+ })
+}
diff --git a/internal/authz/middleware.go b/internal/authz/middleware.go
index f01f262..a35b6b4 100644
--- a/internal/authz/middleware.go
+++ b/internal/authz/middleware.go
@@ -43,7 +43,7 @@ func Authentication(authMap TokenMap, next http.Handler) http.Handler {
func Authorization(adminSvc *admin.Servicer, next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
ctx := req.Context()
- urn := ctx.Value("urn")
+ urn := ctx.Value("urn").(string)
repo := req.URL.Path
action := req.Method
ok, err := adminSvc.Enforce(urn, repo, action)
diff --git a/internal/authz/middleware_test.go b/internal/authz/middleware_test.go
index 5795b3f..cc3f6d1 100644
--- a/internal/authz/middleware_test.go
+++ b/internal/authz/middleware_test.go
@@ -8,7 +8,6 @@ import (
"testing"
"git.ofmax.li/go-git-server/internal/admin"
- "github.com/casbin/casbin/v2"
)
func junkTestHandler() http.HandlerFunc {
@@ -85,10 +84,6 @@ func TestAuthentication(t *testing.T) {
func TestAuthorization(t *testing.T) {
t.Log("Starting authorization tests")
baseURL := "http://test"
- enf, err := casbin.NewSyncedEnforcer("../../auth_model.ini", "../../testpolicy.csv")
- if err != nil {
- t.Fatalf("Failed to load policies\n%s", err)
- }
cases := []struct {
url string
user string
@@ -108,10 +103,12 @@ func TestAuthorization(t *testing.T) {
description: "an unautorized action should yield a 403",
},
}
- svcr := &admin.Servicer{
- enf,
- &admin.ServerRepos{},
- }
+ svcr := admin.NewService(
+ "../../auth_model.ini",
+ "../../testpolicy.csv",
+ "../../gitserver.yaml",
+ "../../repos",
+ false)
for _, tc := range cases {
t.Logf("test case: %s", tc.description)
authHandler := Authorization(svcr, junkTestHandler())
diff --git a/policy.csv b/policy.csv
index 32b32de..ec248b5 100644
--- a/policy.csv
+++ b/policy.csv
@@ -1,13 +1,10 @@
-p, role:admin, config, admin
-p, role:maintainers, /go-git-server/git-upload-pack, POST
-p, role:maintainers, /go-git-server/info/refs, GET
-p, maintainers, /go-git-server/info/refs, GET
-p, maintainers, /go-git-server/git-upload-pack, POST
-p, maintainers, /go-git-server/git-recieve-pack, POST
-p, maintainers, /testmerepo/info/refs, GET
-p, maintainers, /testmerepo/git-upload-pack, POST
-p, maintainers, /testmerepo/git-recieve-pack, POST
+p, role:admin, /mgmt/info/refs, GET
+p, role:admin, /mgmt/git-upload-pack, POST
+p, role:admin, /mgmt/git-receive-pack, POST
+p, role:maintainers, /testmerepo/info/refs, GET
+p, role:maintainers, /testmerepo/git-upload-pack, POST
+p, role:maintainers, /testmerepo/git-receive-pack, POST
g, role:admin, role:maintainers
-g, admin, role:admin
+g, uid:admin, role:admin
g, uid:grumps, role:maintainers
-g, aid:argo, role:bots \ No newline at end of file
+g, aid:argo, role:bots
diff --git a/testpolicy.csv b/testpolicy.csv
index 3420ec1..686784c 100644
--- a/testpolicy.csv
+++ b/testpolicy.csv
@@ -1,3 +1,8 @@
-p,role:test,/repo/url,GET
-
-g,uid:jack,role:test
+p, role:test, /repo/url, GET
+p, role:admin, /mgmt/info/refs, GET
+p, role:admin, /mgmt/git-upload-pack, POST
+p, role:admin, /mgmt/git-receive-pack, POST
+p, role:maintainers, /testmerepo/info/refs, GET
+p, role:maintainers, /testmerepo/git-upload-pack, POST
+p, role:maintainers, /testmerepo/git-receive-pack, POST
+g, uid:jack, role:test \ No newline at end of file