Hello, and thanks @develar for your continued support! My previous issue #2292 was closed prematurely and may have since been buried.
Here's the quick summary: I'm building an app for use by employees at my company. I would like to use GitHub Releases to serve updates from a private repository. Can I do this by setting a token
in the app's package.json
as follows?
"build": {
"appId": "com.github.<owner>.repo",
"productName": "Training Tracker",
"files": [
"dist",
"node_modules",
"main.js",
"package.json"
],
"directories": {
"output": "output"
},
"mac": {
"publish": {
"provider": "github",
"private": true,
"token": "<token>"
},
"target": [
"zip",
"dmg"
]
}
}
My main.js
simply imports electron-updater
and calls autoUpdater.checkForUpdatesAndNotify()
when the app is ready. On startup, however, I get the following error in my logs:
[error] Error: Error: Unable to find latest version on GitHub (https://api.github.com/repos/<owner>/training-tracker/releases/latest), please ensure a production release exists
followed by ERR_CONNECTION_REFUSED
.
Following the link above, I see this in my browser:
{
"message": "Not Found",
"documentation_url": "https://developer.github.com/v3/repos/releases/#get-the-latest-release"
}
What am I missing? Your advice is appreciated!
You need to set process.env.GH_TOKEN
in your main.js instead of package.json
And also set environment variable on your system
@MarkusBansky Thanks for your reply! What about users who do not have a GH_TOKEN
set on their systems? Is main.js
able to reach into their ~/.bash_profile
and set the token when I set process.env.GH_TOKEN
?
You need to set process.env.GH_TOKEN
in main.js only, the environment variable is for your system only, to release the build to github, users should not see the token
Look at the documentation
For what it's worth, I had to go about it a different way. I didn't want to hard-code my GitHub Repo Token inside the application (it's not a read-only token), so as soon as the user of my application logs in, the app retrieves the GH token from my server and uses it to construct the setFeedURL for the updater just before it checks for updates:
ipcMain.on('autoUpdate.status', (evt, token) => {
const data = {
'provider': 'github',
'owner': '<owner-name>',
'repo': '<repo-name>',
'token': token
};
updater.setFeedURL(data);
updater.autoDownload = false;
updater.checkForUpdates();
});
Really glad you guys got to the bottom of how to use setFeedURL! I wasn't able to figure this out from the docs.
A couple notes on GH tokens and private repos:
I had a similar need but was not comfortable with the app storing a GH key. The fundamental problem with GH private repos being used in this way is that GH doesn't have granular ACL. They have a single token that has VERY broad permissions and it's dangerous for anyone outside your org to have access to that. The solution I use: I make a request from the app to my web server (using the "provider: generic" type) which then makes a GH API request for the latest.yml file asset and returns it. Having a web server I control in the middle of the flow between the app and GH allows me to throttle access to just the yml files and binary files (and not allow someone to delete releases, modify info, etc. which can all be done with the private token).
I still need to use setFeedURL in order to test a new build (including updating to it) before distributing it to my install base. setFeedURL allows me to reference a "prerelease" or a "beta" channel so I can QA the upgrade to the new app. Now I just need to build a settings flag I can flip in the frontend of the app!
I think the docs should be updated since saying "don't use setFeedURL" is misleading (especially when in the same doc it describes the method and its parameters). Any takers? If not, I'll try to update and send a PR (but @nbcnc should get credit for this one).
@CydeSwype It costs to the server having to stream the file using transfer bandwidth or you give it through another way?
Update from my earlier comment on Jan 22nd: auto updater has stopped working for GitHub private repos (and public repos from what I understand, though I haven't tested this independently). I have since switched my releases to use AWS S3 bucket and it is working.
See this thread:
https://github.com/electron-userland/electron-builder/issues/2508
@marceloavf yes there is a cost to stream the yml file, but it's a short text file, so cost is nominal (acceptable for our for-profit company's use case). You're right in assuming that the solution I mentioned of sitting in the middle of the request to provide more granular access control requires that the file transfer ALSO needs to go through that same service. If ever the end-user/client is making a direct request to GH with that token, they could discover that and use the token for any other purpose (i.e. deleting releases).
@nbcnc I couldn't get reliable streaming of the binary files from GH with private repo (frequent timeouts on download) so we ended up writing a script to copy new build binaries to Google Cloud Storage. We still reference the yml files in our private GitHub repo that the desktop app checks to see if there's a new binary to download, but when the yml file references a newer version, the desktop app hits our webserver and then redirects that request to GCS for the actual binary. This set up has been very reliable for us.
For what it's worth, I had to go about it a different way. I didn't want to hard-code my GitHub Repo Token inside the application (it's not a read-only token), so as soon as the user of my application logs in, the app retrieves the GH token from my server and uses it to construct the setFeedURL for the updater just before it checks for updates:
ipcMain.on('autoUpdate.status', (evt, token) => { const data = { 'provider': 'github', 'owner': '<owner-name>', 'repo': '<repo-name>', 'token': token }; updater.setFeedURL(data); updater.autoDownload = false; updater.checkForUpdates(); });
I try this way, but it still says in log authentication failed . TOken is invalid.
For what it's worth, I had to go about it a different way. I didn't want to hard-code my GitHub Repo Token inside the application (it's not a read-only token), so as soon as the user of my application logs in, the app retrieves the GH token from my server and uses it to construct the setFeedURL for the updater just before it checks for updates:
ipcMain.on('autoUpdate.status', (evt, token) => { const data = { 'provider': 'github', 'owner': '<owner-name>', 'repo': '<repo-name>', 'token': token }; updater.setFeedURL(data); updater.autoDownload = false; updater.checkForUpdates(); });
I try this way, but it still says in log authentication failed . TOken is invalid.
Hello @hmpargi, I know this seems to be old, but I'm sure you should help your next colleagues with this difficulty.
You must specify that you are accessing a private repository as follows: private: true
See below for a working example so far.
const data = {
provider: 'github',
owner: '<owner-name>',
repo: '<repo-name>',
token: token,
private: true,
};
NOTE: Be careful when using this method.
Most helpful comment
For what it's worth, I had to go about it a different way. I didn't want to hard-code my GitHub Repo Token inside the application (it's not a read-only token), so as soon as the user of my application logs in, the app retrieves the GH token from my server and uses it to construct the setFeedURL for the updater just before it checks for updates: