-
Notifications
You must be signed in to change notification settings - Fork 413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for GitHub app authentication #878
Add support for GitHub app authentication #878
Conversation
Welcome @risset! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have to think more about this when I get a second. It looks pretty clean overall.
Also need to add flags to the manual (at the bottom of the file).
I'll think about how to make e2e tests optional.
_ = resp.Body.Close() | ||
}() | ||
if resp.StatusCode != 201 { | ||
errMessage, err := io.ReadAll(resp.Body) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we bound the read here to 1K or 4K or 32K or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would make sense, should the same apply to the CallAskPassURL
usage of io.ReadAll
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed this before, yeah, it should :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You know what, this is fine. I'm just being paranoid. Doing a bounded copy is nice, but I won't require it here.
main.go
Outdated
@@ -1851,6 +1878,72 @@ func (git *repoSync) CallAskPassURL(ctx context.Context) error { | |||
return nil | |||
} | |||
|
|||
func (git *repoSync) RefreshAppToken(ctx context.Context, githubBaseURL, privateKey string, appID, installationID int) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like the entire set of function names to reflect "GitHubApp" rather than just app, so it's easier to read. Could also do with a nice comment, please
main.go
Outdated
@@ -254,6 +257,19 @@ func main() { | |||
envString("", "GITSYNC_ASKPASS_URL", "GIT_SYNC_ASKPASS_URL", "GIT_ASKPASS_URL"), | |||
"a URL to query for git credentials (username=<value> and password=<value>)") | |||
|
|||
flGithubAPIURL := pflag.String("github-api-url", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's not really a URL is it? Usually a URL includes "scheme" or "protocol", but later you prepend "https://". Also - is this allowed to have paths? E.g. could I say "notgithub.com/mytenant/path" ?
I propose to either make this a URL ("https://host:port/path") or rename it to "host" or "domain".
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah you're right that
I think having it as an actual base URL is better, I'll make this change
main.go
Outdated
@@ -254,6 +257,19 @@ func main() { | |||
envString("", "GITSYNC_ASKPASS_URL", "GIT_SYNC_ASKPASS_URL", "GIT_ASKPASS_URL"), | |||
"a URL to query for git credentials (username=<value> and password=<value>)") | |||
|
|||
flGithubAPIURL := pflag.String("github-api-url", | |||
envString("api.github.com", "GITHUB_API_URL"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this env name special (e.g. used somewhere deep in a library)? I don't think so, right?
All the othe env vars are named "GITSYNC_xyz", so these should probably be "GITSYNC_GITHUB_APP_xyz"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
main.go
Outdated
envString("", "GITHUB_APP_PRIVATE_KEY"), | ||
"the GitHub app private key to use for GitHub app auth") | ||
flGithubAppApplicationID := pflag.Int("github-app-application-id", | ||
envInt(-1, "GITHUB_APP_APPLICATION_ID"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not 0 for default? Is that a valid value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't 100% sure that it couldn't be a valid value, but now you mention it, it doesn't seem likely that the IDs would start at 0 anyway. I'll have them default to 0
main.go
Outdated
flGithubAPIURL := pflag.String("github-api-url", | ||
envString("api.github.com", "GITHUB_API_URL"), | ||
"the API URL to use when making requests to GitHub when using app auth") | ||
flGithubAppPrivateKey := pflag.String("github-app-private-key", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to validate these (see ~ L493). Specifically:
- You can't use these and some other form of auth at the same time
- If user sets this flag, they also need to set the app ID and installation ID
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, we should not put private keys as flags, they are listable via /proc. The --password flag is bad for the same reason.
We should have a way to declare a non-flag which can be set by env but not via CLI. I will think about that. It's going to be a busy few weeks, so please hang tight.
Also, we should be able to pass this in via a file, like --password-file
. For all of these, I'd like it to be possible to use a kubernetes secret and mount a volume, rather than flags/env vars. I'll have to refresh myself on formatting, i think we can only demand one value per file. So maybe we want an alternative --github-app-config=<dir>
with documented files within it, e.g. api-url
(optional), private-key
(required), application-id
(required), and installation-id
(required). That way a user could make a single k8s Secret object with those key, and use a Secret-type volume.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's going to be a busy few weeks, so please hang tight.
No worries! thanks for taking the time for the detailed review, I will address the simple things you brought up in the meantime
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for using a single k8s Secret object with these keys and add validation for them. It would be much easier for the downstream service to provide these values.
main.go
Outdated
@@ -789,6 +806,16 @@ func main() { | |||
} | |||
metricAskpassCount.WithLabelValues(metricKeySuccess).Inc() | |||
} | |||
|
|||
if *flGithubAppPrivateKey != "" && *flGithubAppInstallationID != -1 && *flGithubAppApplicationID != -1 { | |||
if git.appTokenExpiry.Before(time.Now()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't there be some buffer here, so we don't fail TOCTOU ? E.g. require max(20% of the token's lifespan, 30s) or something?
I don't want tokens to be valid here but fail to sync 1 second later, and some of the ops we do can take O(seconds).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense
main.go
Outdated
if *flGithubAppPrivateKey != "" && *flGithubAppInstallationID != -1 && *flGithubAppApplicationID != -1 { | ||
if git.appTokenExpiry.Before(time.Now()) { | ||
if err := git.RefreshAppToken(ctx, *flGithubAPIURL, *flGithubAppPrivateKey, *flGithubAppApplicationID, *flGithubAppInstallationID); err != nil { | ||
metricAskpassCount.WithLabelValues(metricKeyError).Inc() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should have a new metric for this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a different metric - it's not askpass
test_e2e.sh
Outdated
############################################## | ||
# Test github app auth | ||
############################################## | ||
function e2e::github_app_auth() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put this with the other e2e::auth_*
tests and name it e2e::auth_github_app
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
7e947b5
to
834bc50
Compare
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: risset The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
if *flGithubAppInstallationID != 0 { | ||
handleConfigError(log, true, "ERROR: --github-app-installation-id may only be specified when --github-app-private-key-file is specified") | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes the Github app auth mutually exclusive with username/password. What about other auth types, like ssh, cookiefile, or etc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I omitted those because I didn't see them being checked in the existing validations, but I can add them sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is a mess. Was OK when it was 3 mutually exclusive modes, but it's getting out of hand. OK for now, but we should plan a followup which is more declarative feeling and handles the mutual exclusion more automatically.
main.go
Outdated
return err | ||
} | ||
|
||
url, err := url.JoinPath(githubBaseURL, fmt.Sprintf("installations/%d/access_tokens", installationID)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The path should be app/installations/%d/access_tokens
.
main.go
Outdated
@@ -254,6 +257,19 @@ func main() { | |||
envString("", "GITSYNC_ASKPASS_URL", "GIT_SYNC_ASKPASS_URL", "GIT_ASKPASS_URL"), | |||
"a URL to query for git credentials (username=<value> and password=<value>)") | |||
|
|||
flGithubBaseURL := pflag.String("github-base-url", | |||
envString("https://api.github.com/", "GITSYNC_GITHUB_BASE_URL", "GIT_SYNC_GITHUB_BASE_URL"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These flags are new, so you don't need the alternative keys with the GIT_SYNC
prefix for backward compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, addressed this
docs/dev/testing_github_app_auth.md
Outdated
## Step 2: Export the necessary environment variables | ||
|
||
The following environment variables are *required* to run the git-sync github app auth test: | ||
- `GITHUB_APP_PRIVATE_KEY` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These env variables need to have the GITSYNC_
prefix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These ones don't correspond to the actual application env vars though, they're the values that get passed in via flags to the GIT_SYNC
function in the test
docs/dev/testing_github_app_auth.md
Outdated
Should have been saved when creating the app | ||
|
||
### GITHUB_APP_APPLICATION_ID | ||
The value after "App ID" in the app's settings page |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest adding the page URL: https://github.com/settings/apps/<unique_app_name>
While setting up a Github app, I noticed instead of using App ID to get installation tokens, it also supports using the Client ID. I'm wondering have you experimented with the client ID? |
834bc50
to
05e4771
Compare
I didn't know about this, thanks. It appears to be a recent feature: https://github.blog/changelog/2024-05-01-github-apps-can-now-use-the-client-id-to-fetch-installation-tokens/ So the App ID and Client ID can be used interchangeably in this case.
Should we have both the app ID and client ID as parameters and accept either of them, or just replace app ID with client ID? |
261b10d
to
10f7d70
Compare
I would vote for supporting both scenarios. |
Hi @risset , any recent update on addressing the comments in this PR? I'm working on Config Sync. If possible, we would like to leverage this feature in our next minor release in July. |
Hi Nan,
Before we can merge this we need to make sure we can test it properly,
which involves a private key. I have not had the time to play and see how
private it really needs to be, or if maybe we can get it to test via GH
actions.
If you have time, that's where we need to spend it.
…On Mon, Jun 24, 2024, 9:38 PM Nan Yu ***@***.***> wrote:
Hi @risset <https://github.com/risset> , any recent update on addressing
the comments in this PR?
I'm working on Config Sync
<https://cloud.google.com/kubernetes-engine/enterprise/config-sync/docs/overview>.
If possible, we would like to leverage this feature in our next minor
release in July.
—
Reply to this email directly, view it on GitHub
<#878 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABKWAVAJOQGHD6LXYS6QTZDZJDX5HAVCNFSM6AAAAABH6TO2F6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOBXHE3DANBRG4>
.
You are receiving this because you were assigned.Message ID:
***@***.***>
|
Hi, I will be working on this some more over the next few days! I've been having some issues with running |
10f7d70
to
8aab47c
Compare
Thanks for the update. Did you run the e2e test with a public repo or a private repo? |
I've been testing with a private repo. I'll double check the instructions and how I've set the app up etc. in case I missed something |
Does the app you created definitely have read-only or read-write access for When I re-run the tests with either of those not true, I also get the repo not found error. |
No worries. I think it was the issue with my testing account. I created a robot Github account. The account is flagged and requires reinstatement. It works with my personal account. |
Nice! Hopefully we can get this over the line. I'm still not quite sure how getting the tests to run properly via actions will work. |
Regarding the e2e test for the github app integration, I created a robot GitHub account, a GitHub app, along with a private repository under the account. After that, I set up the required environment variables in GitHub Secret in my personal fork. All e2e test passed with changes in risset#1: https://github.com/nan-yu/git-sync/actions/runs/9947634472. Can we use the robot account for testing, @thockin ? |
8aab47c
to
d7ecc0b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also update the README? Basically just delete the last section, build the binary and run it with --man >> README.md, then add the last triple-ticks.
Other than my own automated and manual testing, it looks good.
main.go
Outdated
envString("", "GITSYNC_GITHUB_APP_PRIVATE_KEY_FILE"), | ||
"the file from which the private key for GitHub app auth will be sourced") | ||
flGithubAppClientID := pflag.String("github-app-client-id", | ||
envString("", "GTSYNC_GITHUB_APP_CLIENT_ID"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: GTSYNC should be GITSYNC.
Same on the next one, too
if *flGithubAppInstallationID != 0 { | ||
handleConfigError(log, true, "ERROR: --github-app-installation-id may only be specified when --github-app-private-key-file is specified") | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is a mess. Was OK when it was 3 mutually exclusive modes, but it's getting out of hand. OK for now, but we should plan a followup which is more declarative feeling and handles the mutual exclusion more automatically.
main.go
Outdated
if *flGithubAppPrivateKey != "" && *flGithubAppInstallationID != -1 && *flGithubAppApplicationID != -1 { | ||
if git.appTokenExpiry.Before(time.Now()) { | ||
if err := git.RefreshAppToken(ctx, *flGithubAPIURL, *flGithubAppPrivateKey, *flGithubAppApplicationID, *flGithubAppInstallationID); err != nil { | ||
metricAskpassCount.WithLabelValues(metricKeyError).Inc() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a different metric - it's not askpass
_ = resp.Body.Close() | ||
}() | ||
if resp.StatusCode != 201 { | ||
errMessage, err := io.ReadAll(resp.Body) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed this before, yeah, it should :)
d7ecc0b
to
3ea1801
Compare
Have updated to address recent feedback ! Pardon my ignorance here but I'm still a bit unsure on how best to address your comment on the usage of Also I've added one, but not sure if you feel a metric is actually needed for this feature, it was just sloppiness from me having the askpass code fragment left in there before ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks mostly good to me. I would like to enable the e2e tests for this new feature.
Feel free to port over changes in https://github.com/risset/git-sync/pull/1/files.
main.go
Outdated
@@ -2492,6 +2665,22 @@ AUTHENTICATION | |||
When --cookie-file ($GITSYNC_COOKIE_FILE) is specified, the | |||
associated cookies can contain authentication information. | |||
|
|||
github app | |||
When --github-app-private-key-file ($GITSYNC_GITHUB_APP_PRIVATE_KEY_FILE), | |||
--github-app-application-id ($GITSYNC_GITHUB_APP_APPLICATION_ID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--github-app-application-id or --github-app-client-id
test_e2e.sh
Outdated
@@ -295,6 +295,7 @@ function GIT_SYNC() { | |||
-v "$DOT_SSH/1/id_test":"/ssh/secret.1":ro \ | |||
-v "$DOT_SSH/2/id_test":"/ssh/secret.2":ro \ | |||
-v "$DOT_SSH/3/id_test":"/ssh/secret.3":ro \ | |||
-v "$(pwd)/$GITHUB_APP_PRIVATE_KEY_FILE":"/github_app_private_key.pem":ro \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This requires the github app private key file to be located at the same directory. It won't work with the e2e test in the GitHub Actions Workflow.
I'm not sure if you get a chance to take a look at risset#1. Basically, it loads the private key from GitHub Secrets and stored it in a temp file. It would be good to incorporate it in this PR and enables the e2e test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will take a look at that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I updated risset#1 to make the github app auth test skippable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merged this in now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am AFK for a couple weeks, and don't want to merge until I can run some.manual tests, but it looks great
main.go
Outdated
|
||
metricRefreshGitHubAppTokenCount = prometheus.NewCounterVec(prometheus.CounterOpts{ | ||
Name: "git_sync_refresh_github_app_token_count", | ||
Help: "How many times github app token was refreshed, partitioned by state (success, error)", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super nit: "the GitHub app token"
main.go
Outdated
@@ -838,6 +896,17 @@ func main() { | |||
} | |||
metricAskpassCount.WithLabelValues(metricKeySuccess).Inc() | |||
} | |||
|
|||
if *flGithubAppPrivateKeyFile != "" && *flGithubAppInstallationID != 0 && (*flGithubAppApplicationID != 0 || *flGithubAppClientID != "") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be considering the newly added environment also?
main.go
Outdated
func (git *repoSync) RefreshGitHubAppToken(ctx context.Context, githubBaseURL, privateKeyFile, clientID string, appID, installationID int) error { | ||
git.log.V(3).Info("refreshing GitHub app token") | ||
|
||
privateKeyBytes, err := os.ReadFile(privateKeyFile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this consider the environment var key?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot about this, added it now
_ = resp.Body.Close() | ||
}() | ||
if resp.StatusCode != 201 { | ||
errMessage, err := io.ReadAll(resp.Body) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You know what, this is fine. I'm just being paranoid. Doing a bounded copy is nice, but I won't require it here.
main.go
Outdated
|
||
--github-app-application-id <int>, $GITSYNC_GITHUB_APP_APPLICATION_ID | ||
The app ID of the GitHub app used for GitHub app authentication. | ||
One of --github-app-application-id or --github-app-client-id is required. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...when GitHub app authentication is used.
Same below
10d816d
to
12d712e
Compare
Signed-off-by: Liam Wyllie <[email protected]>
The GitHub app e2e test requires a GitHub app to be created and installed, and also requires a few environment variables to be set. This commit updates the GitHub action workflow by providing the environment variables which can be set via GitHub Secret. GitHub Secrests cannot start with `GITHUB_`. Hence, this commit prepends `TEST_` to the env variables. It also updates how GitHub app private key file is set. It can be set by either `TEST_GITHUB_APP_PRIVATE_KEY` or `TEST_GITHUB_APP_PRIVATE_KEY_FILE`.
12d712e
to
ba2fe67
Compare
# Set the trap to call the final_cleanup function on exit. | ||
trap final_cleanup EXIT | ||
|
||
skip_github_app_test="${SKIP_GITHUB_APP_TEST:-false}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think skipping may be a more user friendly default, since in most cases a developer won't have github app credentials ready to use
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense as long as the github action workflow doesn't skip the github app test.
skip_github_app_test="${SKIP_GITHUB_APP_TEST:-false}" | ||
required_env_vars=() | ||
LOCAL_GITHUB_APP_PRIVATE_KEY_FILE="github_app_private_key.pem" | ||
GITHUB_APP_PRIVATE_KEY_MOUNT="" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be declared as an empty array so that it is properly expanded below when the volume mount is not added.
e.g.
GITHUB_APP_PRIVATE_KEY_MOUNT=()
...
# Mount the GitHub App private key file to the git-sync container
GITHUB_APP_PRIVATE_KEY_MOUNT+=(-v "${TEST_GITHUB_APP_PRIVATE_KEY_FILE}:/${LOCAL_GITHUB_APP_PRIVATE_KEY_FILE}:ro")
...
"${GITHUB_APP_PRIVATE_KEY_MOUNT[@]}" \
"${GIT_SYNC_E2E_IMAGE}" \
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing it to an empty array looks good to me. Thanks for pointing it out.
Yes, the ball is in my court to evaluate testing. I apologize, it has been a chaotic few weeks since I got back from holiday. I have not forgotten it. |
if [[ ! -v TEST_GITHUB_APP_PRIVATE_KEY_FILE || -z "${TEST_GITHUB_APP_PRIVATE_KEY_FILE}" ]]; then | ||
TEST_GITHUB_APP_PRIVATE_KEY_FILE="${DIR}/${LOCAL_GITHUB_APP_PRIVATE_KEY_FILE}" | ||
fi | ||
echo "${TEST_GITHUB_APP_PRIVATE_KEY}" > "${TEST_GITHUB_APP_PRIVATE_KEY_FILE}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm worried about this path, seems like an opportunity to blow away a file we shouldn't. Maybe we can make a temp file and use that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TEST_GITHUB_APP_PRIVATE_KEY_FILE
points to a temp file when it is either unset or blank. Another option is to always use the temp file regardless of whether the variable is set, i.e., remove the if condition in line 222.
if [[ -v TEST_GITHUB_APP_PRIVATE_KEY && -n "${TEST_GITHUB_APP_PRIVATE_KEY}" ]]; then
TEST_GITHUB_APP_PRIVATE_KEY_FILE="${DIR}/${LOCAL_GITHUB_APP_PRIVATE_KEY_FILE}"
echo "${TEST_GITHUB_APP_PRIVATE_KEY}" > "${TEST_GITHUB_APP_PRIVATE_KEY_FILE}"
fi
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm making a few edits as I look at this, will post them here. May not finish today.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I dug into the testing in depth and set up my own app. With the below diff I am happy with this PR, but I have not yet looked at making CI work (with GH secrets)
diff --git a/test_e2e.sh b/test_e2e.sh
index 9b2023f..142d7c1 100755
--- a/test_e2e.sh
+++ b/test_e2e.sh
@@ -41,6 +41,11 @@ function fail() {
return 42
}
+function skip() {
+ echo "SKIP" >&3
+ return 43
+}
+
function pass() {
echo "PASS"
}
@@ -204,37 +209,43 @@ function final_cleanup() {
# Set the trap to call the final_cleanup function on exit.
trap final_cleanup EXIT
-skip_github_app_test="${SKIP_GITHUB_APP_TEST:-false}"
+skip_github_app_test="${SKIP_GITHUB_APP_TEST:-true}"
required_env_vars=()
LOCAL_GITHUB_APP_PRIVATE_KEY_FILE="github_app_private_key.pem"
-GITHUB_APP_PRIVATE_KEY_MOUNT=""
+GITHUB_APP_PRIVATE_KEY_MOUNT=()
if [[ "${skip_github_app_test}" != "true" ]]; then
required_env_vars=(
"TEST_GITHUB_APP_AUTH_TEST_REPO"
"TEST_GITHUB_APP_APPLICATION_ID"
"TEST_GITHUB_APP_INSTALLATION_ID"
"TEST_GITHUB_APP_CLIENT_ID"
- "TEST_GITHUB_APP_PRIVATE_KEY_FILE"
)
- # TEST_GITHUB_APP_PRIVATE_KEY, if set, overrides TEST_GITHUB_APP_PRIVATE_KEY_FILE
- if [[ -v TEST_GITHUB_APP_PRIVATE_KEY && -n "${TEST_GITHUB_APP_PRIVATE_KEY}" ]]; then
- if [[ ! -v TEST_GITHUB_APP_PRIVATE_KEY_FILE || -z "${TEST_GITHUB_APP_PRIVATE_KEY_FILE}" ]]; then
- TEST_GITHUB_APP_PRIVATE_KEY_FILE="${DIR}/${LOCAL_GITHUB_APP_PRIVATE_KEY_FILE}"
- fi
- echo "${TEST_GITHUB_APP_PRIVATE_KEY}" > "${TEST_GITHUB_APP_PRIVATE_KEY_FILE}"
+ if [[ -n "${TEST_GITHUB_APP_PRIVATE_KEY_FILE:-}" && -n "${TEST_GITHUB_APP_PRIVATE_KEY:-}" ]]; then
+ echo "ERROR: Both TEST_GITHUB_APP_PRIVATE_KEY_FILE and TEST_GITHUB_APP_PRIVATE_KEY were specified."
+ exit 1
+ fi
+ if [[ -n "${TEST_GITHUB_APP_PRIVATE_KEY_FILE:-}" ]]; then
+ cp "${TEST_GITHUB_APP_PRIVATE_KEY_FILE}" "${DIR}/${LOCAL_GITHUB_APP_PRIVATE_KEY_FILE}"
+ elif [[ -n "${TEST_GITHUB_APP_PRIVATE_KEY:-}" ]]; then
+ echo "${TEST_GITHUB_APP_PRIVATE_KEY}" > "${DIR}/${LOCAL_GITHUB_APP_PRIVATE_KEY_FILE}"
+ else
+ echo "ERROR: Neither TEST_GITHUB_APP_PRIVATE_KEY_FILE nor TEST_GITHUB_APP_PRIVATE_KEY was specified."
+ echo " Either provide a value or skip this test (SKIP_GITHUB_APP_TEST=true)."
+ exit 1
fi
# Validate all required environment variables for the github-app-auth tests are provided.
for var in "${required_env_vars[@]}"; do
if [[ ! -v "${var}" ]]; then
- echo "Error: Required environment variable '${var}' is not set or empty. Either provide a value or skip the GitHub App test by setting SKIP_GITHUB_APP_TEST to 'true'."
+ echo "ERROR: Required environment variable '${var}' is not set."
+ echo " Either provide a value or skip this test (SKIP_GITHUB_APP_TEST=true)."
exit 1
fi
done
# Mount the GitHub App private key file to the git-sync container
- GITHUB_APP_PRIVATE_KEY_MOUNT=(-v "${TEST_GITHUB_APP_PRIVATE_KEY_FILE}":"/${LOCAL_GITHUB_APP_PRIVATE_KEY_FILE}":ro)
+ GITHUB_APP_PRIVATE_KEY_MOUNT=(-v "${DIR}/${LOCAL_GITHUB_APP_PRIVATE_KEY_FILE}":"/${LOCAL_GITHUB_APP_PRIVATE_KEY_FILE}":ro)
fi
# WORK is temp space and in reset for each testcase.
@@ -2232,7 +2243,7 @@ function e2e::auth_askpass_url_slow_start() {
##############################################
function e2e::auth_github_app_application_id() {
if [[ "${skip_github_app_test}" == "true" ]]; then
- return
+ skip
fi
GIT_SYNC \
--one-time \
@@ -2247,7 +2258,7 @@ function e2e::auth_github_app_application_id() {
function e2e::auth_github_app_client_id() {
if [[ "${skip_github_app_test}" == "true" ]]; then
- return
+ skip
fi
GIT_SYNC \
--one-time \
@@ -3658,6 +3669,8 @@ for t; do
run_test RUN_RET "${TEST_FN}" >"${LOG}.${RUN}" 2>&1
if [[ "$RUN_RET" == 0 ]]; then
pass
+ elif [[ "$RUN_RET" == 43 ]]; then
+ true # do nothing
else
TEST_RET=1
if [[ "$RUN_RET" != 42 ]]; then
Since this is a kubernetes repo, I'll have to see about making the kubernetes org own the app |
Any plans on releasing this soon? This could help our team a lot. |
I'm going to merge this and followup. I Still don't have CI for GH apps up, though. |
Related issue: #877
Currently the
e2e::github_app_auth
test should work locally, if the correct env vars are set. I've tested the feature that way before creating the PR. Ideally it would be possible to run it in the GHA workflow. One way I thought that might be feasible is if an app was created and installed to a particular (private) repo, and then its private key was stored as a git-sync repository secret.Some information about GitHub app authentication: https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app