Skip to content

Commit 8732f2a

Browse files
authored
Merge pull request #55 from karpikpl/feature/configuration
2 parents 1009cfa + 4a2f5bb commit 8732f2a

40 files changed

+10842
-3577
lines changed

.dockerignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
.env
1+
**/.env
2+
**/.env.local
3+
.env*
4+
.dockerignore
5+
**/node_modules/
6+
api/public
27
.dockerignore
38
.git
49
.gitignore

.env

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ VUE_APP_GITHUB_TEAM=
1616
# Determines the GitHub Personal Access Token to use for API calls.
1717
# Create with scopes copilot, manage_billing:copilot or manage_billing:enterprise, read:enterprise AND read:org
1818
VUE_APP_GITHUB_TOKEN=
19+
20+
# GitHub Api Url
21+
# for proxy api - set to /api/github defaults to https://api.github.com
22+
VUE_APP_GITHUB_API=
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Build and push Docker image for Proxy
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
# Allows you to run this workflow manually from the Actions tab
9+
workflow_dispatch:
10+
11+
permissions:
12+
packages: write
13+
14+
jobs:
15+
push_to_ghcr:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout GitHub Action
19+
uses: actions/checkout@v4
20+
21+
- name: Login to GitHub Container Registry
22+
uses: docker/login-action@v3
23+
with:
24+
registry: ghcr.io
25+
username: ${{ github.actor }}
26+
password: ${{ secrets.GITHUB_TOKEN }}
27+
28+
- name: Build and Push Docker Image
29+
run: |
30+
GITHUB_REPO="${GITHUB_REPO,,}-with-proxy" # convert repo name to lowercase as required by docker
31+
echo "building docker image in repository '$GITHUB_REPO' ..."
32+
docker build -f api.Dockerfile --label "org.opencontainers.image.title=copilot-metrics-viewer-with-proxy" --label "org.opencontainers.image.description=Metrics viewer with proxy for GitHub Copilot usage" --label "org.opencontainers.image.source=$GITHUB_REPO" -t ghcr.io/$GITHUB_REPO:latest .
33+
docker push ghcr.io/$GITHUB_REPO:latest
34+
env:
35+
GITHUB_REPO: ${{ github.repository }}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,7 @@ pnpm-debug.log*
2121
*.njsproj
2222
*.sln
2323
*.sw?
24+
.azure
25+
26+
api/public
27+
test.http

DEPLOYMENT.md

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# Deployment of Copilot Metrics Viewer
2+
3+
There are a few ways to deploy the Copilot Metrics Viewer, depending on the type of metrics (Organization/Enterprise) and the level of control required.
4+
5+
The app runs in a Docker container, so it can be deployed anywhere containers are hosted (AWS, GCP, Azure, Kubernetes, etc.).
6+
7+
## Authentication to GitHub
8+
9+
The Metrics Viewer can be integrated with GitHub application authentication, which authenticates the user and verifies their permissions to view the metrics. This option is recommended since it doesn't use Personal Access Tokens. The downside of using a GitHub application is that it can only authorize users to view metrics at the organization level (no support for Enterprise).
10+
11+
With a Personal Access Token, user credentials are not verified, and the application simply renders Copilot metrics fetched using the PAT stored in the backend.
12+
13+
## Authentication for Copilot Metrics Viewer
14+
15+
By default Azure Deployments deploy a web app available on the public Internet without authentication (unless GitHub app is used).
16+
17+
Application can be easily secured in azure using built-in features like Authentication settings on ACA/AppService (EasyAuth on Azure). Azure Container Apps and App Services allow for adding IP restrictions on ingress. Both can also be deployed using private networking architectures.
18+
19+
Options below provide most basic and cost effective ways of hosting copilot-metrics-viewer.
20+
21+
## Scenario 1: One-click Azure Deployment
22+
23+
The simplest way to deploy is to use the "one-click" option that creates resources in Azure. The deployment includes:
24+
25+
* Azure Container App with a consumption environment
26+
* Azure Log Analytics Workspace
27+
28+
![Azure ARM Deployment](./azure-deploy/arm-deployment.png)
29+
30+
Application will use a pre-built docker image hosted in GitHub registry: `ghcr.io/github-copilot-resources/copilot-metrics-viewer-with-proxy`.
31+
32+
**Prerequisites:** Contributor permission to a resource group in Azure and a subscription with the `Microsoft.App` resource provider enabled.
33+
34+
> [!IMPORTANT]
35+
> **Estimated cost** for running this in Azure is about $1 per month, as Container Apps have the first 2 million requests each month free.
36+
37+
1. **Option 1 - Using a Personal Access Token in the Backend**:
38+
39+
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fgithub-copilot-resources%2Fcopilot-metrics-viewer%2Fmain%2Fazure-deploy%2Fwith-token%2Fazuredeploy.json)
40+
41+
2. **Option 2 - Using GitHub App Registration and GitHub Authentication**:
42+
43+
When using this method, [register your app in Github first](#github-app-registration).
44+
45+
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fgithub-copilot-resources%2Fcopilot-metrics-viewer%2Fmain%2Fazure-deploy%2Fwith-app-registration%2Fazuredeploy.json)
46+
47+
**Important**: After deploying Option 2, the redirect URI needs to be updated with the URL of the deployed container app.
48+
49+
Go to: `https://github.com/organizations/<your-org>/settings/apps/<your-app>` or in the UI to the settings of the registered application and add the following redirect URLs:
50+
51+
```
52+
http://<YOUR Container APP URL>.azurecontainerapps.io/callback
53+
https://<YOUR Container APP URL>.azurecontainerapps.io/callback
54+
```
55+
56+
### Deployment with private networking
57+
58+
> [!CAUTION]
59+
> When deploying to a private network, specify a subnet (at least /23) for the Azure Container Apps Environment.
60+
App deployment does not create any DNS entries for the application, in order to create a private DNS Zone linked to provided Virtual Network, follow up the deployment with DNS deployment targeting same resource group:
61+
>
62+
>[![DNS Zone deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fgithub-copilot-resources%2Fcopilot-metrics-viewer%2Fmain%2Fazure-deploy%2Fdns%2Fazuredeploy.json)
63+
64+
## Scenario 2: Azure Deployment with azd
65+
66+
If more control over the deployed container image is needed, an infrastructure-as-code option has been provided using Azure Bicep. The application can be deployed using the [Azure Developer CLI](https://aka.ms/azd) (azd).
67+
68+
In this scenario, the container is built from the source code locally, which provides additional opportunities to modify, scan, etc.
69+
70+
**Prerequisites:**
71+
- Contributor permission to a subscription in Azure with the `Microsoft.App` resource provider enabled.
72+
- Permissions for creating role assignments.
73+
- Azure CLI (az), Azure Developer CLI (azd) and Docker installed locally.
74+
75+
> [!IMPORTANT]
76+
> **Estimated cost** for running this in Azure is about $10 per month, Container Apps have the first 2 million requests each month free and Container Registry costs about $5.
77+
78+
The deployment creates:
79+
80+
* Azure Resource Group
81+
* Azure Container App with a consumption environment
82+
* Azure Container Registry
83+
* Azure Log Analytics Workspace
84+
* Azure Application Insights
85+
* Azure Key Vault
86+
87+
![AZD Deployment](./azure-deploy/azd-deployment.png)
88+
89+
Before running `azd up`, configure GitHub variables:
90+
91+
```bash
92+
azd env set VUE_APP_SCOPE <organization/enterprise>
93+
# when using organization
94+
azd env set VUE_APP_GITHUB_ORG <org name>
95+
# when using enterprise
96+
azd env set VUE_APP_GITHUB_ENT <ent name>
97+
azd env set VUE_APP_GITHUB_API /api/github
98+
azd env set GITHUB_CLIENT_ID <client id>
99+
azd env set GITHUB_CLIENT_SECRET <client secret for the GH App>
100+
```
101+
102+
## Scenario 3: Deploying the container
103+
104+
Application can be deployed anywhere where containers can run and configured via environment variables:
105+
106+
For GitHub App:
107+
108+
```bash
109+
docker run -it --rm -p 3000:3000 \
110+
-e VUE_APP_SCOPE=organization \
111+
-e VUE_APP_GITHUB_API=/api/github \
112+
-e VUE_APP_GITHUB_ORG=<org name> \
113+
-e GITHUB_CLIENT_ID=<client id> \
114+
-e GITHUB_CLIENT_SECRET=<client secret for the GH App> \
115+
-e SESSION_SECRET=<random string> \
116+
ghcr.io/github-copilot-resources/copilot-metrics-viewer-with-proxy
117+
```
118+
119+
or with PAT token and enterprise:
120+
121+
```bash
122+
docker run -it --rm -p 3000:3000 \
123+
-e VUE_APP_SCOPE=enterprise \
124+
-e VUE_APP_GITHUB_API=/api/github \
125+
-e VUE_APP_GITHUB_ENT=<enterprise name> \
126+
-e VUE_APP_GITHUB_TOKEN=<github PAT> \
127+
-e SESSION_SECRET=<random string> \
128+
ghcr.io/github-copilot-resources/copilot-metrics-viewer-with-proxy
129+
```
130+
131+
or with PAT token and organization:
132+
133+
```bash
134+
docker run -it --rm -p 3000:3000 \
135+
-e VUE_APP_SCOPE=organization \
136+
-e VUE_APP_GITHUB_API=/api/github \
137+
-e VUE_APP_GITHUB_ORG=<org name> \
138+
-e VUE_APP_GITHUB_TOKEN=<github PAT> \
139+
-e SESSION_SECRET=<random string> \
140+
ghcr.io/github-copilot-resources/copilot-metrics-viewer-with-proxy
141+
```
142+
143+
## Github App Registration
144+
145+
While it is possible to run the API Proxy without GitHub app registration and with a hardcoded token, it is not the recommended way.
146+
147+
To register a new GitHub App, follow these steps:
148+
149+
> [!TIP]
150+
> Navigate using link: replace `<your_org>` with your organization name and open this link:
151+
[https://github.com/organizations/<your_org>/settings/apps](https://github.com/organizations/<your_org>/settings/apps)
152+
153+
or navigate using UI:
154+
1. Go to your organization's settings.
155+
2. Navigate to "Developer settings".
156+
3. Select "GitHub Apps".
157+
4. Click "New GitHub App".
158+
159+
1. Set a unique name.
160+
2. Provide a home page URL: your company URL or just `http://localhost`.
161+
3. Add a callback URL for `http://localhost:3000/callback`. (We'll add the real redirect URL after the application is deployed.)
162+
4. Uncheck the "Webhook -> Active" checkbox.
163+
5. Set the scopes:
164+
- Select **Organization permissions**.
165+
- Under **GitHub Copilot Business**, select **Access: Read-only**.
166+
6. Click on 'Create GitHub App' and, in the following page, click on 'Generate a new client secret'. (IMPORTANT: _**Save it for later**_)
167+
7. Install the app in the organization:
168+
- Go to "Install App".
169+
- Select your organization.
170+
171+
Note the `Client ID` and `Private Key`.

README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,58 @@ docker run -p 8080:80 --env-file ./.env copilot-metrics-viewer
150150
```
151151
The application will be accessible at http://localhost:8080
152152

153+
## Running with API Proxy
154+
155+
Project can run with an API proxy which hides GitHub tokens and is secure enough to be deployed.
156+
Api Proxy project is in `\api` directory. Vue app makes the calls to `/api/github` which then are proxied to `https://api.github.com` with appropriate bearer token.
157+
158+
Proxy can authenticate user using GitHub App. In order to do that, following environment variables are required:
159+
160+
* `GITHUB_CLIENT_ID` - client Id of the GitHub App registered and installed in the enterprise/org with permissions listed above.
161+
* `GITHUB_CLIENT_SECRET` - client secret of the GitHub App
162+
* `SESSION_SECRET` - random string for securing session state
163+
164+
It's also possible to run with **PAT Token**, see examples below for required variables.
165+
166+
For local development register `http://localhost:3000/callback` as GH App callback Uri.
167+
For deployed version use the Uri of your app.
168+
169+
To build and run the app with API proxy:
170+
171+
```bash
172+
docker build -t copilot-metrics-viewer-with-proxy -f api.Dockerfile .
173+
```
174+
175+
To run:
176+
177+
```bash
178+
docker run -it --rm -p 8080:3000 --env-file ./.env copilot-metrics-viewer-with-proxy
179+
```
180+
181+
Proxy can also run with token hardcoded on the backend (which hides it from frontend calls), here's a sample:
182+
183+
```bash
184+
docker run -it --rm -p 3000:3000 \
185+
-e VUE_APP_SCOPE=enterprise \
186+
-e VUE_APP_GITHUB_API=/api/github \
187+
-e VUE_APP_GITHUB_ENT=<enterprise name> \
188+
-e VUE_APP_GITHUB_TOKEN=<github PAT> \
189+
-e SESSION_SECRET=<random string> \
190+
copilot-metrics-viewer-with-proxy
191+
```
192+
193+
or
194+
195+
```bash
196+
docker run -it --rm -p 3000:3000 \
197+
-e VUE_APP_SCOPE=organization \
198+
-e VUE_APP_GITHUB_API=/api/github \
199+
-e VUE_APP_GITHUB_ORG=<org name> \
200+
-e VUE_APP_GITHUB_TOKEN=<github PAT> \
201+
-e SESSION_SECRET=<random string> \
202+
copilot-metrics-viewer-with-proxy
203+
```
204+
153205
## License
154206

155207
This project is licensed under the terms of the MIT open source license. Please refer to [MIT](./LICENSE.txt) for the full terms.

api.Dockerfile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Stage 1: Build the Vue.js application
2+
FROM node:14 as build-stage
3+
WORKDIR /app
4+
COPY package*.json ./
5+
RUN npm install
6+
COPY . .
7+
# this will tokenize the app
8+
RUN npm run build
9+
10+
# Stage 2: Prepare the Node.js API
11+
FROM node:14 as api-stage
12+
WORKDIR /api
13+
# Copy package.json and other necessary files for the API
14+
COPY api/package*.json ./
15+
RUN npm install
16+
# Copy the rest of your API source code
17+
COPY api/ .
18+
19+
# Copy the built Vue.js app from the previous stage
20+
COPY --from=build-stage /app/dist /api/public
21+
COPY --from=build-stage /app/dist/assets/app-config.js /api/app-config.template.js
22+
23+
# install gettext-base for envsubst
24+
RUN apt-get update && apt-get install -y gettext-base
25+
26+
# Expose the port your API will run on
27+
EXPOSE 3000
28+
29+
# Command to run your API (and serve your Vue.js app)
30+
RUN chmod +x /api/docker-entrypoint.api/entrypoint.sh
31+
ENTRYPOINT ["/api/docker-entrypoint.api/entrypoint.sh"]

api/.env

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Client Id from GitHub App installed on the organization
2+
GITHUB_CLIENT_ID=
3+
4+
# Client Secret from GitHub App installed on the organization
5+
GITHUB_CLIENT_SECRET=
6+
7+
# Secret for the session - random string for session
8+
SESSION_SECRET=
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/bash
2+
3+
configTemplateFile=/api/app-config.template.js
4+
configTargetFile=/api/public/assets/app-config.js
5+
6+
# Temporarily unset VUE_APP_GITHUB_TOKEN
7+
# this is requiered until vue app is updated to remove tokens from it
8+
tempToken=$VUE_APP_GITHUB_TOKEN
9+
unset VUE_APP_GITHUB_TOKEN
10+
11+
envsubst <"$configTemplateFile" >"$configTargetFile"
12+
13+
# Restore VUE_APP_GITHUB_TOKEN
14+
export VUE_APP_GITHUB_TOKEN=$tempToken
15+
16+
node server.mjs

0 commit comments

Comments
 (0)