Following the instructions on this SO question I was able to create a repo for an organization that I own using the GitHub REST API and the R packages httr and RCurl. Now, I'm having issues deleting the repo using the API.
I created an OAuth app on GitHub and gave the app access to my organization. Then I ran the code below to create a token with the delete_repo scope.
library(httr)
library(RCurl)
# 1. Find OAuth settings for github:
# http://developer.github.com/v3/oauth/
oauth_endpoints("github")
# 2. Register an application at https://github.com/settings/applications
# Insert your values below - if secret is omitted, it will look it up in
# the GITHUB_CONSUMER_SECRET environmental variable.
#
# Use http://localhost:1410 as the callback url
myapp <- oauth_app("TestApp", "app-number","secret-number")
scope <- 'delete_repo'
# 3. Get OAuth credentials
github_token <- oauth2.0_token(oauth_endpoints("github"),scope=scope, myapp)
Per the GitHub API v3 developer guide, the URL to create a new repo in an organization is
https://api.github.com/orgs/:org/repos
Using this URL I was able to create a private repo for my organization named 'Reliability' by running:
#Push repository to Github
url_c = "https://api.github.com/orgs/Reliability/repos"
data = list("name"= "newRepo", "private" = "true")
POST(url = url_c, body = data, config(token = github_token))
To delete a repo, the developer guide states that the URL should be of the form
DELETE repos/:owner/:repo
For an organizational repo, I interpret that this URL should be
https://api.github.com/orgs/:org/repos/:owner/:repo
However, when I run the following code I get a response of 404 not found.
# Delete repository from Github organization
url_d = "https://api.github.com/orgs/Reliability/repos/Auburngrads/newRepo"
DELETE(url = url_d, config(token = github_token))
What am I missing?
The wording in the GitHub developer guide is misleading with respect to URL that should be used to delete organizational repos using the REST API.
The developer guide states that to delete a repo, the URL should be of the form
DELETE repos/:owner/:repo
However, for an organizational repo, the URL should be of the form
DELETE repos/:org/:repo
I was able to successfully delete a repo from my organization called 'Reliability' by 1) ensuring that my app token had the appropriate delete_repo scope and 2) running the following code
# Delete repository from Github organization
url_d = "https://api.github.com/repos/Reliability/newRepo"
DELETE(url = url_d, config(token = github_token))
Related
Background
I am working on a custom theme for my WordPress site which I would like to manage from a private GitHub repo. (This theme will never be pushed into the WordPress market place) The general idea would be that I use the repo to manage the code and then once I tag a new version, the tag would trigger an update for the WordPress theme.
I have this pattern working using the following as a template:
https://github.com/krafit/wp-gitlab-updater
(Yes, I know the repo is for Gitlab and not GitHub)
Since my repo is private, I will need to generate a user token to allow the theme to be updated. And because the user token is capable of accessing all my private repos, the idea of sharing the user token with another plugin is discomforting from a security standpoint. (Meaning, I'm uncomfortable using a plugin like: https://github.com/afragen/git-updater)
Question
The problem is that GitHub has deprecated the use of access_token as a query string parameter, so all tokens must be sent over as an Authorization header.
How do I add an authorization header to the request WordPress sends to download the artifact?
What I've Tried
When I check for new tags I use the code:
protected function fetch_tags_from_repo( $git_url, $repo, $access_token ) {
$request_url = "$git_url/repos/$repo/tags?access_token=$access_token";
$args = [
"headers" => [
"Accept" => "application/vnd.github.v3+json",
"Authorization" => "token " . $access_token
]
];
$request = wp_safe_remote_get( $request_url, $args );
return $request;
}
This works without any issues. However...
During the pre_set_site_transient_update_themes hook I return an object that looks like:
$transient->response[ $theme['name'] ]['theme'] = $theme['name'];
$transient->response[ $theme['name'] ]['new_version'] = $latest_version;
$transient->response[ $theme['name'] ]['package'] = $theme_package;
The problem is, I have no way of adding an Authorization header to the transient response object. Therefore, when WP later tries to download the artifact, it fails.
Note: The $theme_package string is a URL which looks like:
$theme_package = "$git_url/repos/$repo/zipball/refs/tags/$latest_version";
Any support appreciated, thank you!
Honestly, this problem has been exhausting and enough is enough...
Answer
Eject from GitHub and use Gitlab because they still support access_token as a header. They have unlimited free private repos <5gb storage.
If you are planning to distribute the private repo with a license I recommend you not to expose your access credentials in the script.
Instead you should use the GitHub PHP API together with a SSH Key that you setup in your repo settings or a GitHub App with access permission granted on your repo.
Here is a solid SDK to start from:
https://github.com/KnpLabs/php-github-api
Alternatively as you suggested it in your answer, a third party service could be used to manage the credentials on your behalf.
Gitlab is a nice generic and low cost option but if you are looking for something dedicated to Wordpress development I recommend WP Package Editor (WP2E)
Among other things the service uses a registered GitHub App to pull the latest version from public / private GitHub repositories:
https://github.com/marketplace/wp-package-editor
This is quoted from the documentation regarding how it is implemented with GitHub:
For a script to be successfully imported to the library of repositories and later be synchronized as an installer dependency there are 4 conditions :
The GitHub App must be connected to a WP2E account
The “read-only” access to the repository must be granted to the WP2E GitHub App
The script must be a valid WP theme or plugin
The repository must have at least one “release” on GitHub
Note: In order to synchronize with the GitHub account/repo the GitHub App should be integrated via the saas panel ( not directly via the GitHub Marketplace )
I'm trying to use GitHub Actions to query the GitHub API using an OAuth 2.0 token through an R script. It works fine on my local machine when I run the code, where a browser window pops up indicating "Waiting for authentication in browser..." that I can manually close. When run through GitHub Actions, the workflow hangs at the "Waiting for authentication in browser..." since it's on a remote machine.
I'm using a custom R script with the httr library. The API credentials are stored as secrets for the repository I'm trying to query.
library(httr)
gh_key <- Sys.getenv('GH_KEY')
gh_secret <- Sys.getenv('GH_SECRET')
# setup app credentials
myapp <- oauth_app(appname = "data-in-r",
key = gh_key,
secret = gh_secret)
# get oauth credentials
github_token <- oauth2.0_token(oauth_endpoints('github'), app = myapp, cache = F)
# use api
gtoken <- config(token = github_token)
# get list of remote files in data folder
req <- GET("https://api.github.com/repos/tbep-tech/piney-point/contents/data", gtoken)
When the script is run through GitHub Actions, it looks like as below, where I had to manually cancel the workflow since it was hung at the browser step.
Is there a workaround for skipping the browser step so it will run on GitHub Actions? The offending repo is here.
You cannot use the 3-legged variant of OAuth2.0 (aka "web-application flow") in a headless environment like Github Actions.
If you want to use OAuth (I list other possibilities below), then you need to utilize what gitlab calls the "device-flow". See github documentation.
In this flow, there is no redirect to a given URL, so the app does not need a browser window. Instead it displays a code to the user. The user must the enter that code on a fixed URL (https://github.com/login/device). As soon as this is done, the app can request the authentication token. (So the app must keep polling until the user has entered the code).
Unfortunately, httr does not have nice wrapper functions for this variant, so you have to do the calls yourself. It can work like this:
library(httr)
app_id <- "*redacted*"
r <- POST("https://github.com/login/device/code",
body = list(
client_id = app_id,
scope = "user repo delete_repo" #Scope must be given! https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps
))
device_code <- content(r)$device_code
print(paste0("Enter the code ", content(r)$user_code, " at ", content(r)$verification_uri))
## NOTE: In reality this request has to run in a loop, until the user has entered the code und the request succeeds.
## For the demo we can execute it manually after the code has been entered.
r <- POST("https://github.com/login/oauth/access_token",
body = list(
client_id = app_id,
device_code = device_code,
grant_type = "urn:ietf:params:oauth:grant-type:device_code"
))
token <- content(r)$access_token
## create and delete a private testrepository to check if everything worked
r <-
POST("https://api.github.com/user/repos",
add_headers(Authorization = paste("token", token)),
body = list(name = "testrepo",
private = TRUE,
auto_init = FALSE),
encode = "json")
r <- DELETE(paste0("https://api.github.com/repos/", content(r)$full_name),
add_headers(Authorization = paste("token", token)))
I have seen that there is httr2, and that it offers convenience functions for this flow. I have however never used it and do not know if it already works reliable. See here.
Since this flow still requires user interaction, you may be better of with one of the following variants (I do not know if they fit your use case.):
Basic Auth:
You can define what github calls a "personal access token" beforehand. With this token you can authenticate without further interaction. Creation is described here. In R you can use it most easily together with httr::authenticate.
GITHUB_TOKEN:
Github automatically creates special secrets specifically Github Actions. These can be used to execute actions in the containing repository. For more info see here.
I managed to generate keys and tokens to be able to access google cloud storage files from within the r console.
However, upon executing the code below, i run into below error -
Error: $installed not found in JSON - have you downloaded the correct JSON file?
(Service account client > Desktop, not Service Account Keys)
While the code has been addressed/provided from previous SO post, the error is still enigmatic to me.
-- SO post below
Accessing files from Google cloud storage in RStudio
-- full code below
rm(list = ls(all.names = TRUE))
options(java.parameters = "-Xmx8000m")
library(googleCloudStorageR)
library(googleAuthR)
library(jsonlite)
# for working in google cloud storage
GCS_AUTH_FILE = "serviceaccount.json"
GAR_CLIENT_WEB_JSON = "Oauthclient.json"
# fromJSON(GCS_AUTH_FILE)
# fromJSON(GAR_CLIENT_WEB_JSON)
gar_auth_service(GCS_AUTH_FILE)
#set the scope
gar_set_client(scopes = c("https://www.googleapis.com/auth/devstorage.read_write",
"https://www.googleapis.com/auth/cloud-platform"), json = GAR_CLIENT_WEB_JSON
)
It seems that you are not using the correct JSON file. I found this Github post that mentions how to configure this correctly.
These are the steps:
Enable Google Cloud Storage API
Credentials >> Create Credentials >> OAuth Client ID >> Other
Save the JSON file as something like my-ClientID-credentials.json
Credentials >> Create Credentials >> Service Account Key
Save the JSON file as something like my-service-account-credentials.json
This is the code mentioned in the post
# Google cloud storage
# Setup
library(googleCloudStorageR)
options(googleAuthR.scopes.selected = "https://www.googleapis.com/auth/devstorage.full_control")
# Authenticate ClientID
googleAuthR::gar_set_client("path/to/my-ClientID-credentials.json")
# Authenticate service account
Sys.setenv("GCS_AUTH_FILE" = "full/path/to/my-service-account-credentials.json")
googleCloudStorageR::gcs_auth()
## Get bucket info
gcs_list_buckets(projectId = "my-project")
I have a Client ID and Client Secret after having set up an application in github, I'm not sure what the URL or the callback URL is meant to be for that...which i think is causing me problems
I also have a private repo that I would like the application to access...
The way I would like to access the private repo would be via R, so I have found some packages that might help including ROAuth and oauth, but I'm not too sure how to go about using these to get the tokens, as they tend to require a bunch of URLs to make the requests from, and I am unsure as to what the URLs are to get these requests for tokens.
Looking at http://developer.github.com/v3/oauth/ doesn't seem to be amazingly helpful in terms of my inputs for oauth or Oauth2Authorize functions for each of the respective packages.
The end goal is to source files from the private repo, since source_url('private.repo.file.url') doesn't work
I tried the basic authentication using curl through bash, but wasn't able to find a token.
Any walkthrough examples of how to go about doing this would be greatly appreciated.
P.S. this is a follow up question from r sourcing private repos from github
You just need to create an oAuth token at https://github.com/settings/tokens
and get required file via GitHub API using code like below
library(RCurl)
library(devtools)
jsonRawFile <- fromJSON(getURL("https://api.github.com/repos/USERNAME/REPONAME/contents/filename.R",
httpheader = c(Authorization = "token 38ebb0393fe1757ffde9c45d81adzzzzzzzzz",
"User-Agent" = "RCurl"),
.opts = list(ssl.verifypeer = FALSE)))
source_url(jsonRawFile$download_url)
The format of Authorization header should be strictly "token " + your_token_from_account.
I'm trying to use Hackpad's API in R. Unlike the example in httr, the Hackpad documentation
1. uses oauth 1.0 and
2. says that the requests should be signed with your credentials.
I do not completely understand how to do the 2nd part in R (with any library). I understand how to use the request, authorize, and access URLs -- but those are not provided for Hackpad (as far as I can tell).
Here is what I tried in R (to no success):
library(httr)
myapp <- oauth_app("hackpad",
key = mykey,
secret = mysecret)
hackpad_token <- oauth1.0_token(oauth_endpoint(authorize = 'https://hackpad.com/api/1.0/',
request = 'https://hackpad.com/api/1.0/',
access = 'https://hackpad.com/api/1.0/'),
myapp)
and also
req <- GET("https://hackpad.com/api/1.0/pad/k9bpcEeOo2Q/content/latest.html",
config = authenticate(user=myuser,
password=mypass))
which tries to return the API documentation content.
Thank you for your help