Skip to content

Commit

Permalink
Proxy support (#21)
Browse files Browse the repository at this point in the history
* Update README.md to include proxy configuration support
* Extending proxy support via parameters, adding tests, updating action node 16 and bumping version to 2.0.0
* Adding squid configuration

Co-authored-by: martinprodriguez <88494794+martinprodriguez@users.noreply.github.com>
Co-authored-by: Peter Murray <peter-murray@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 11, 2022
1 parent e8782d6 commit 7b0e459
Show file tree
Hide file tree
Showing 10 changed files with 449 additions and 143 deletions.
69 changes: 69 additions & 0 deletions .github/workflows/test_repository_installed_proxy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Tests this action success by the application already being installed on the repository

name: Test Success - repository - installed - with proxy

on:
push:
workflow_dispatch:
inputs:
branch:
description: The name of the branch to checkout for the action
required: true
default: main

jobs:
test:
runs-on: ubuntu-latest

# services:
# squid:
# image: ubuntu/squid
# ports:
# - 3128/tcp
# volumes:
# - '${{ github.workspace }}:/var/log/squid'
# options: --dns 8.8.8.8

steps:
- name: Checkout specified branch
if: github.event_name == 'workflow_dispatch'
uses: actions/checkout@v3
with:
ref: ${{ github.event.inputs.branch }}

- name: Checkout
if: github.event_name != 'workflow_dispatch'
uses: actions/checkout@v3

- name: Start Squid Proxy container
run: |
mkdir ${{ github.workspace }}/squid
sudo chown proxy:proxy ${{ github.workspace }}/squid
docker run -dit --name squid -p 3128:3128 -v ${{ github.workspace }}/test/squid.conf:/etc/squid/squid.conf -v ${{ github.workspace }}/squid:/var/log/squid ubuntu/squid:latest
sleep 5
docker logs squid
docker inspect squid
curl http://localhost:3128
- name: Use action
id: use_action
continue-on-error: true
uses: ./
with:
application_id: ${{ secrets.APPLICATION_ID }}
application_private_key: ${{ secrets.APPLICATION_PRIVATE_KEY }}
https_proxy: http://localhost:3128

- name: Show Squid Logs and stop container
run: |
docker stop squid
ls -la ${{ github.workspace }}/squid
sudo cat ${{ github.workspace }}/squid/access.log
- name: Use token to read details
uses: actions/github-script@v2
with:
github-token: ${{ steps.use_action.outputs.token }}
script: |
const repo = await github.repos.get(context.repo);
console.log(JSON.stringify(repo, null, 2));
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ generates for you or Base64 encode it in the secret.
* `permissions`: The optional limited permissions to request, specifying this allows you to request a subset of the permissions for the underlying GitHub Application. Defaults to all permissions available to the GitHub Application when not specified. Must be provided in a comma separated list of token permissions e.g. `issues:read, secrets:write, packages:read`
* `organization`: An optional organization name if the GitHub Application is installed at the Organization level (instead of the repository).
* `github_api_base_url`: An optional URl to the GitHub API, this will be read and loaded from the runner environment by default, but you might be bridging access to a secondary GHES instance or from GHES to GHEC, you can utilize this to make sure the Octokit library is talking to the right GitHub instance.
* `https_proxy`: An optional proxy to use for connecting with the GitHub instance. If the runner has `HTTP_PROXY` or `HTTPS_PROXY` specified as environment variables it will attempt to use those if this parameter is not specified.

#### Examples
Get a token with all the permissions of the GitHub Application:
Expand Down Expand Up @@ -149,6 +150,29 @@ jobs:
with:
....
```
### Proxy

You can specify a proxy server directory using the `https_proxy` parameter in your `with` settings, or by falling back to
using any environment variables used to provide a proxy reference; `HTTP_PROXY` or `HTTPS_PROXY` (or lowercase variants e.g. `http_proxy`).
If defined, the request will use the proxy to route the connection to the GitHub instance.

```yaml
jobs:
get-temp-token:
runs-on: ubuntu-latest
steps:
- name: Get Token
id: get_workflow_token
uses: peter-murray/workflow-application-token-action@v1
with:
application_id: ${{ secrets.APPLICATION_ID }}
application_private_key: ${{ secrets.APPLICATION_PRIVATE_KEY }}
organization: octodemo
https_proxy: http://my-squid-proxy:3128
....
```

### References
https://docs.github.com/en/developers/apps/authenticating-with-github-apps#authenticating-as-an-installation
6 changes: 5 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,16 @@ inputs:
description: The GitHub API base URL to use, no needed it working within the same GitHub instance as the workflow as it will get picked up from the environment
required: false

https_proxy:
description: Option proxy server for making the requests
required: false

outputs:
token:
description: A valid token representing the Application that can be used to access what the Application has been scoped to access.

runs:
using: node12
using: node16
main: dist/index.js

branding:
Expand Down
6 changes: 3 additions & 3 deletions dist/index.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ async function run() {
const privateKey = getRequiredInputValue('application_private_key')
, applicationId = getRequiredInputValue('application_id')
, githubApiBaseUrl = core.getInput('github_api_base_url') || process.env['GITHUB_API_URL'] || 'https://api.github.com'
, httpsProxy = core.getInput('https_proxy')
;
app = await githubApplication.create(privateKey, applicationId, githubApiBaseUrl);
app = await githubApplication.create(privateKey, applicationId, githubApiBaseUrl, null, httpsProxy);
} catch(err) {
fail(err, 'Failed to initialize GitHub Application connection using provided id and private key');
}
Expand Down
29 changes: 25 additions & 4 deletions lib/github-application.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
const jwt = require('jsonwebtoken')
, github = require('@actions/github')
, PrivateKey = require('./private-key')
;
, HttpsProxyAgent = require('https-proxy-agent')
;

module.exports.create = (privateKey, applicationId, baseApiUrl, timeout) => {
module.exports.create = (privateKey, applicationId, baseApiUrl, timeout, proxy) => {
const app = new GitHubApplication(privateKey, applicationId, baseApiUrl);

return app.connect(timeout)
return app.connect(timeout, proxy)
.then(() => {
return app;
});
Expand All @@ -24,7 +25,7 @@ class GitHubApplication {
this._client = null;
}

connect(validSeconds) {
connect(validSeconds, proxy) {
const self = this
, secondsNow = Math.floor(Date.now() / 1000)
, expireInSeconds = validSeconds || 60
Expand All @@ -42,6 +43,12 @@ class GitHubApplication {
if (this.githubApiBaseUrl) {
octokitOptions.baseUrl = this.githubApiBaseUrl;
}

const request = {
agent: getProxyAgent(proxy),
timeout: 5000
};
octokitOptions.request = request;
this._client = new github.getOctokit(token, octokitOptions);

return this.client.request('GET /app', {
Expand Down Expand Up @@ -169,4 +176,18 @@ function _validateVariableValue(variableName, value) {
throw new Error(`${variableName} must be provided contained no valid characters other than whitespace`)
}
return result;
}

function getProxyAgent(proxy) {
const envProxy = proxy
|| process.env.http_proxy
|| process.env.HTTP_PROXY
|| process.env.https_proxy
|| process.env.HTTPS_PROXY
;

if (envProxy) {
return new HttpsProxyAgent(envProxy);
}
return null;
}
46 changes: 45 additions & 1 deletion lib/github-application.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,50 @@ describe('GitHubApplication', () => {
expect(repo).to.have.property('data');
expect(repo.data).to.have.property('owner').to.have.property('login').to.equal(ownerName);
expect(repo.data).to.have.property('name').to.equal(repoName);
});

describe('Using proxy server', () => {

describe('Installed Application - GitHub.com', function () {

this.timeout( 10 * 1000);

const TEST_APPLICATION_NAME = 'test';

beforeEach(async () => {
app = await gitHubApp.create(
testValues.getApplicationPrivateKey(TEST_APPLICATION_NAME),
testValues.getApplicationId(TEST_APPLICATION_NAME),
null,
null,
`http://${process.env.SQUID_HOST}:3128`
);
});

it('should be able to get access token for a repository installation', async () => {
const repoInstall = await app.getRepositoryInstallation(
testValues.getTestRepositoryOwner(TEST_APPLICATION_NAME),
testValues.getTestRepository(TEST_APPLICATION_NAME)
)
, accessToken = await app.getInstallationAccessToken(repoInstall.id)
;
expect(accessToken).to.have.property('token');

// Use the token to access the repository
const client = new github.getOctokit(accessToken.token)
, repoName = testValues.getTestRepository(TEST_APPLICATION_NAME)
, ownerName = testValues.getTestRepositoryOwner(TEST_APPLICATION_NAME)
, repo = await client.rest.repos.get({
owner: ownerName,
repo: repoName,
});

expect(repo).to.have.property('status').to.equal(200);
expect(repo).to.have.property('data');
expect(repo.data).to.have.property('owner').to.have.property('login').to.equal(ownerName);
expect(repo.data).to.have.property('name').to.equal(repoName);
});
});
})
});
});
});
Loading

0 comments on commit 7b0e459

Please sign in to comment.