Compare commits
11 Commits
v202209260
...
v202211070
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4b91e9993 | ||
|
|
e30fad8050 | ||
|
|
d7e1ea845e | ||
|
|
51dff542d6 | ||
|
|
ef922b8e3b | ||
|
|
6d732db1cf | ||
|
|
86c578bdf2 | ||
|
|
621a30f411 | ||
|
|
0ae35c149f | ||
|
|
4f5ae77ae9 | ||
|
|
db79671e1d |
@@ -24,8 +24,6 @@ When there are machines which have access to both the public internet and the GH
|
||||
|
||||
**Arguments:**
|
||||
|
||||
- `actions-admin-user` _(optional)_
|
||||
The name of the Actions admin user, which will be used for updating the chosen action. To use the default user, pass `actions-admin`. If not set, the impersonation is disabled. Note that `site_admin` scope is required in the token for the impersonation to work.
|
||||
- `cache-dir` _(required)_
|
||||
The directory in which to cache repositories as they are synced. This speeds up re-syncing.
|
||||
- `destination-url` _(required)_
|
||||
@@ -38,6 +36,8 @@ When there are machines which have access to both the public internet and the GH
|
||||
A comma-separated list of repositories to be synced. Each entry follows the format of `repo-name`.
|
||||
- `repo-name-list-file` _(optional)_
|
||||
A path to a file containing a newline separated list of repositories to be synced. Each entry follows the format of `repo-name`.
|
||||
- `actions-admin-user` _(optional)_
|
||||
The name of the Actions admin user, which will be used for updating the chosen action. To use the default user, pass `actions-admin`. If not set, the impersonation is disabled. Note that `site_admin` scope is required in the token for the impersonation to work.
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
@@ -86,8 +86,6 @@ When no machine has access to both the public internet and the GHES instance:
|
||||
|
||||
**Arguments:**
|
||||
|
||||
- `actions-admin-user` _(optional)_
|
||||
The name of the Actions admin user, which will be used for updating the chosen action. To use the default user, pass `actions-admin`. If not set, the impersonation is disabled. Note that `site_admin` scope is required in the token for the impersonation to work.
|
||||
- `cache-dir` _(required)_
|
||||
The directory containing the repositories fetched using the `pull` command.
|
||||
- `destination-url` _(required)_
|
||||
@@ -96,6 +94,8 @@ When no machine has access to both the public internet and the GHES instance:
|
||||
A personal access token to authenticate against the GHES instance when uploading repositories. See [Destination token scopes](#destination-token-scopes) below.
|
||||
- `repo-name`, `repo-name-list` or `repo-name-list-file` _(optional)_
|
||||
Limit push to specific repositories in the cache directory.
|
||||
- `actions-admin-user` _(optional)_
|
||||
The name of the Actions admin user, which will be used for updating the chosen action. To use the default user, pass `actions-admin`. If not set, the impersonation is disabled. Note that `site_admin` scope is required in the token for the impersonation to work.
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
|
||||
@@ -123,6 +123,16 @@ function test_push() {
|
||||
push "pushing to authenticated user's account"
|
||||
assert_dest_sha "monalisa/new-repo" "heads/main" "e9009d51dd6da2c363d1d14779c53dd27fcb0c52" "updating monalisa/new-repo"
|
||||
|
||||
# Push to GHAE with impersonation
|
||||
setup_cache "org-already-exists/ghae-repo:heads/main:e9009d51dd6da2c363d1d14779c53dd27fcb0c52"
|
||||
setup_dest "org-already-exists/ghae-repo:heads/main:a5984bb887dd2fcdc2892cd906d6f004844d1142"
|
||||
push_impersonation "ghae-admin" "pushing to GHAE repo"
|
||||
|
||||
# Push to GHES with impersonation
|
||||
setup_cache "org-already-exists/ghes-repo:heads/main:e9009d51dd6da2c363d1d14779c53dd27fcb0c52"
|
||||
setup_dest "org-already-exists/ghes-repo:heads/main:a5984bb887dd2fcdc2892cd906d6f004844d1142"
|
||||
push_impersonation "ghes-admin" "pushing to GHES repo"
|
||||
|
||||
echo "all push tests passed successfully"
|
||||
}
|
||||
|
||||
@@ -313,6 +323,17 @@ function push2args() {
|
||||
fail $3
|
||||
}
|
||||
|
||||
function push_impersonation() {
|
||||
bin/actions-sync push \
|
||||
--cache-dir "test/tmp/cache" \
|
||||
--disable-push-git-auth \
|
||||
--destination-token "token" \
|
||||
--destination-url "http://localhost:$DEST_API_PORT" \
|
||||
--actions-admin-user $1 \
|
||||
&> $OUTPUT ||
|
||||
fail "$2"
|
||||
}
|
||||
|
||||
function sync() {
|
||||
bin/actions-sync sync \
|
||||
--cache-dir "test/tmp/cache" \
|
||||
|
||||
48
src/push.go
48
src/push.go
@@ -82,7 +82,7 @@ func GetImpersonationToken(ctx context.Context, flags *PushFlags) (string, error
|
||||
fmt.Printf("these are the scopes we have for the current token `%s` ...\n", scopesHeader)
|
||||
|
||||
if !strings.Contains(scopesHeader, "site_admin") {
|
||||
return "", errors.Wrap(err, "the current token doesn't have the `site_admin` scope, the impersonation function requires the `site_admin` permission to be able to impersonate.")
|
||||
return "", errors.New("the current token doesn't have the `site_admin` scope, the impersonation function requires the `site_admin` permission to be able to impersonate")
|
||||
}
|
||||
|
||||
isAE := rootResponse.Header.Get(enterpriseVersionHeaderKey) == enterpriseAegisVersionHeaderValue
|
||||
@@ -179,21 +179,16 @@ func PushWithGitImpl(ctx context.Context, flags *PushFlags, repoName string, ghC
|
||||
}
|
||||
|
||||
func getOrCreateGitHubRepo(ctx context.Context, client *github.Client, repoName, ownerName string) (*github.Repository, error) {
|
||||
repo := &github.Repository{
|
||||
Name: github.String(repoName),
|
||||
HasIssues: github.Bool(false),
|
||||
HasWiki: github.Bool(false),
|
||||
HasPages: github.Bool(false),
|
||||
HasProjects: github.Bool(false),
|
||||
}
|
||||
|
||||
currentUser, _, err := client.Users.Get(ctx, "")
|
||||
// retrieve user associated to authentication credentials provided
|
||||
currentUser, userResponse, err := client.Users.Get(ctx, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error retrieving authenticated user")
|
||||
}
|
||||
if currentUser == nil || currentUser.Login == nil {
|
||||
return nil, errors.New("error retrieving authenticated user's login name")
|
||||
}
|
||||
// checking if we talk to GHAE
|
||||
isAE := userResponse.Header.Get(enterpriseVersionHeaderKey) == enterpriseAegisVersionHeaderValue
|
||||
|
||||
// check if the owner refers to the authenticated user or an organization.
|
||||
var createRepoOrgName string
|
||||
@@ -209,15 +204,36 @@ func getOrCreateGitHubRepo(ctx context.Context, client *github.Client, repoName,
|
||||
}
|
||||
}
|
||||
|
||||
ghRepo, resp, err := client.Repositories.Create(ctx, createRepoOrgName, repo)
|
||||
// check if repository already exists
|
||||
ghRepo, resp, err := client.Repositories.Get(ctx, ownerName, repoName)
|
||||
|
||||
if err == nil {
|
||||
fmt.Printf("Created repo `%s/%s`\n", ownerName, repoName)
|
||||
} else if resp != nil && resp.StatusCode == 422 {
|
||||
ghRepo, _, err = client.Repositories.Get(ctx, ownerName, repoName)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Printf("Existing repo `%s/%s`\n", ownerName, repoName)
|
||||
} else if resp != nil && resp.StatusCode == 404 {
|
||||
// repo not existing yet - try to create
|
||||
visibility := github.String("public")
|
||||
if isAE {
|
||||
visibility = github.String("internal")
|
||||
}
|
||||
repo := &github.Repository{
|
||||
Name: github.String(repoName),
|
||||
HasIssues: github.Bool(false),
|
||||
HasWiki: github.Bool(false),
|
||||
HasPages: github.Bool(false),
|
||||
HasProjects: github.Bool(false),
|
||||
Visibility: visibility,
|
||||
}
|
||||
|
||||
ghRepo, _, err = client.Repositories.Create(ctx, createRepoOrgName, repo)
|
||||
if err == nil {
|
||||
fmt.Printf("Created repo `%s/%s`\n", ownerName, repoName)
|
||||
} else {
|
||||
return nil, errors.Wrapf(err, "error creating repository %s/%s", ownerName, repoName)
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, errors.Wrapf(err, "error creating repository %s/%s", ownerName, repoName)
|
||||
}
|
||||
|
||||
if ghRepo == nil {
|
||||
return nil, errors.New("error repository is nil")
|
||||
}
|
||||
|
||||
@@ -8,15 +8,20 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-github/v43/github"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
var authenticatedLogin string = "monalisa"
|
||||
var existingOrg string = "org-already-exists"
|
||||
var existingRepo string = "repo-already-exists"
|
||||
|
||||
const existingOrg string = "org-already-exists"
|
||||
const existingRepo string = "repo-already-exists"
|
||||
const ghaeRepo string = "ghae-repo"
|
||||
const xOAuthScopesHeader = "X-OAuth-Scopes"
|
||||
|
||||
//nolint:gocyclo
|
||||
func main() {
|
||||
var port, gitDaemonURL string
|
||||
flag.StringVar(&port, "p", "", "")
|
||||
@@ -28,9 +33,14 @@ func main() {
|
||||
|
||||
r.HandleFunc("/api/v3", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("x-github-enterprise-version", "GitHub AE")
|
||||
w.Header().Set(xOAuthScopesHeader, "site_admin")
|
||||
})
|
||||
|
||||
r.HandleFunc("/api/v3/user", func(w http.ResponseWriter, r *http.Request) {
|
||||
token := r.Header.Get("Authorization")
|
||||
if strings.Contains(token, "ghaetoken") {
|
||||
w.Header().Set("x-github-enterprise-version", "GitHub AE")
|
||||
}
|
||||
currentUser := github.User{Login: &authenticatedLogin}
|
||||
b, _ := json.Marshal(currentUser)
|
||||
_, err := w.Write(b)
|
||||
@@ -39,8 +49,7 @@ func main() {
|
||||
}
|
||||
})
|
||||
|
||||
r.HandleFunc("/api/v3/admin/users/actions-admin/authorizations", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("x-github-enterprise-version", "GitHub AE")
|
||||
r.HandleFunc("/api/v3/admin/users/ghes-admin/authorizations", func(w http.ResponseWriter, r *http.Request) {
|
||||
token := "token"
|
||||
auth := github.Authorization{Token: &token}
|
||||
b, _ := json.Marshal(auth)
|
||||
@@ -50,6 +59,17 @@ func main() {
|
||||
}
|
||||
}).Methods("POST")
|
||||
|
||||
r.HandleFunc("/api/v3/admin/users/ghae-admin/authorizations", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("x-github-enterprise-version", "GitHub AE")
|
||||
token := "ghaetoken"
|
||||
auth := github.Authorization{Token: &token}
|
||||
b, _ := json.Marshal(auth)
|
||||
_, err := w.Write(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}).Methods("POST")
|
||||
|
||||
r.HandleFunc("/api/v3/admin/organizations", func(w http.ResponseWriter, r *http.Request) {
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
@@ -114,16 +134,35 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
var repoReq struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Visibility string `json:"visibility,omitempty"`
|
||||
}
|
||||
err = json.Unmarshal(b, &repoReq)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if repoReq.Name == "repo-already-exists" {
|
||||
var errString string = ""
|
||||
// check visibility requirements
|
||||
if repoReq.Name == ghaeRepo {
|
||||
if repoReq.Visibility != "internal" {
|
||||
errString = fmt.Sprintf("Provided repo visibility %s for GHAE must be internal", repoReq.Visibility)
|
||||
}
|
||||
} else {
|
||||
if repoReq.Visibility != "public" {
|
||||
errString = fmt.Sprintf("Provided repo visibility %s for GHES must be public", repoReq.Visibility)
|
||||
}
|
||||
}
|
||||
|
||||
// check if we are testing existing Repo
|
||||
if repoReq.Name == existingRepo {
|
||||
errString = fmt.Sprintf("Repo %s already exists", html.EscapeString(repoReq.Name))
|
||||
}
|
||||
|
||||
// if there is an error throw it back
|
||||
if errString != "" {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
_, err := w.Write([]byte(fmt.Sprintf("Repo %s already exists", html.EscapeString(repoReq.Name))))
|
||||
_, err := w.Write([]byte(errString))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user