Skip to content
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

docs: Revamp docs to highlight use cases and explain EMU attribution flow #332

Merged
merged 2 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 9 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ For a video overview, check out [this short presentation and demo video](https:/
>
> This app is still a work in progress and is pre-1.0 _public beta_. We are actively working on improving it with beta testers, and if you're interested in using it for your organization, [we'd love to hear from you](https://github.com/github-community-projects/private-mirrors/issues/new)!

## Background
## Problem Statement

Enterprises struggle with how to let their developers contribute to open source projects. Most are not opposed, in principle, to contributing back to the projects they rely upon. Many are enthusiastic about becoming better open source citizens, and understand the reputational and technical benefits that working in open source can accrue to the business. However, real and perceived security concerns make this process difficult at best and impossible at worst for companies.

Expand Down Expand Up @@ -61,7 +61,7 @@ The app uses an intermediary public fork to merge the private mirror into, and t

## Hosting

You'll need to self-host the app. See the section on [Developing](#developing) for more information.
You'll need to self-host the app. See the section on [Developing](docs/developing.md) for more information.

This app was created with the idea of self-hosting in mind and can be deployed to any hosting provider that supports Next.js/Docker.

Expand All @@ -80,7 +80,7 @@ docker compose up

We recommend using Node 20.x or higher, though any Node LTS version >18 should work.

Once it's running, you'll need to create a GitHub App and configure it to point to your deployment. See the [Developing — GitHub App](#github-app) section for more information.
Once it's running, you'll need to create a GitHub App and configure it to point to your deployment. See the [Developing — GitHub App](docs/developing.md#github-app) section for more information.

## Integrating the App into GHEC

Expand All @@ -101,56 +101,13 @@ The authentication of the UI will still need to be a user's github.com user, but

Once the app is installed, follow this document on [Using the Private Mirrors App](docs/using-the-app.md) to get the repository fork and mirrors set up for work.

## Developing
## Further Reading

### Environment

Create a new `.env` file from the `.env.example` file

```sh
cp .env.example .env
```

### GitHub App

1. Create a new GitHub App [here](https://github.com/settings/apps/new)
2. There's an App manifest in the repo that lays out all the permissions and webhook events needed and can be found [here](./app.yml).
3. Copy all the secrets, credentials, and IDs into the `.env` file

### Webapp

This is a webapp built with Next.js. You can find the Next.js documentation [here](https://nextjs.org/docs).

#### Install dependencies

```sh
npm i
```

#### Start the application

```sh
npm run dev
```

You should be up and running on [http://localhost:3000](http://localhost:3000)!

#### Testing Webhooks

Webhooks are an important part of this application, they listen for events that happen to your organization and trigger the app to do things like create branch protections or sync code between forks.

We have our own webhook proxy that you can use to test webhooks locally. You will need to set `PUBLIC_ORG` (and `PRIVATE_ORG` if you want to test with a different organization) in your `.env` file to your GitHub organization name.

### GitHub Requirements

We recommend that you have a dedicated GitHub organization for your contributions. This will allow you to keep your contributions separate from your organization's daily operations.

> We have added support for GitHub Enterprise Managed Users (EMUs) and GitHub Enterprise Cloud (GHEC) in the app. If you are using GitHub Enterprise, you will need to make sure that the app is installed on your GitHub Enterprise instance.

Permissions:

- The GitHub App must be installed on the organization(s) you plan on contributing from
- Currently, any member of the organization can access the app and create additional private mirror repositories
- [Contributing with Confidence: Capital One's open source contribution workflows](https://www.youtube.com/watch?v=boWJs4lASfY) - Talk about PMA by @ahpook and @riley-kohler at GitHub Universe 2024
- [Developing](docs/developing.md)
- [Using the App](docs/using-the-app.md)
- [Architecture](docs/architecture.md)
- [Attribution Flow](docs/attribution-flow.md)

## License

Expand Down
39 changes: 39 additions & 0 deletions docs/attribution-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Attribution Flow

## Overview

Enteprise Managed Users (EMU) are a [feature of GitHub Enterprise Cloud](https://docs.github.com/en/enterprise-cloud@latest/admin/managing-iam/understanding-iam-for-enterprises/about-enterprise-managed-users) which provides a "walled garden" user account that cannot interact with public repositories on github.com, including filing issues, commenting on discussions, and raising pull requests. Large organizations use EMUs to provide a tighter degree of control over their user accounts, but this control can come at the cost of participation in open source communities.

One of the goals of the Private Mirrors App is to enable contributions from EMUs, and this doc explains how to do it.

## How Attributions Work

Git commits under the hood are associated with email addresses. GitHub makes a convenient association between email addresses and user accounts for purposes of attribution, contribution graphs, etc, but it's email underneath all that. So in the case where a contribution is crossing user accounts and especially across EMU boundaries, as long as there is some association between the public github.com user and an email address, the attributions will be linked up automatically.

For contributions which originate on a private mirror and PMA syncs to the public fork, this linkage can go in either direction:

- the public github.com account can have the EMU account's email address added as a secondary address, and commits made with that email will be attributed to the user. **or**
- a user inside the EMU boundary can configure their git client to commit with an address associated with their public account. :arrow_left:

We recommend the second option because it does not expose any internal information, namely the user's email address, to the public contribution graph.

Sometimes stakeholders will raise the idea of funneling all contributions through a "role" account like `@bigcorp-opensource`, but we strongly discourage this. It's both bad for maintainers (people want contributions from humans not corporations) and for contributors (the attribution of their work to the open source world is often a primary driver for wanting to contribute in the first place).

## Configuring git-config

So, to ensure that contributions made by an EMU are properly attributed to their public GitHub account, the user needs to configure their local git-config to use an email address associated with their public account. This should be done at the repository level, when they are working in a private mirror managed by PMA, rather than as a global configuration.

```sh
git config --local user.email "[email protected]"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some advanced git config examples that can make this automatic based on the remote or directory in which the repository exists. This also makes it easier to configure things like commit signing keys.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's awesome, happy to iterate on this - I'd definitely say that as I'm talking to new people about PMA, the attribution question (and more generally, how things work across the EMU<>Public boundary) is the number one concern. So having more detailed guidance here can only help!

```

## Example

Here is an example of how the attribution flow works:

1. An EMU user configures their local git-config to use the email address associated with their public GitHub account.
2. The user makes a contribution to a private mirror repository.
3. The contribution is reviewed and merged into the private mirror's default branch.
4. The Private Mirrors App automatically syncs the private mirror to the public fork.
5. The contribution is now visible in the public fork and is attributed to the user's public GitHub account.
6. The user can then switch to their public account and open a pull request from the public fork to the upstream repository, and the contribution will be properly attributed to their public identity.
132 changes: 132 additions & 0 deletions docs/developing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Developing

## Prerequisites

- Node.js (version 18 or higher)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to list a single or couple of supported versions (likely Node.js 20 and/or 22). We likely do not want to support non-LTS Node.js versions, and our dependencies also may limit the Node.js versions they support.

I'm happy to split an issue off to discuss this further. It would include

  1. Specify in engines (and devEngines, which is a newer feature but not sure if it is on the Node.js included version or npm yet) the versions we support.
  2. Configure GitHub Actions to use these specific versions of Node.js (right now they use the defaults from the runners and no node setup at all, from what I can tell). Using the setup actions could also help with dependency caching.
  3. Add a .nvmrc or .node-version file and document how developers of the app can use open source tools to install the proper Node.js version for the app.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue #333 has been created to continue this discussion!

- npm (version 6 or higher)
- Docker (optional, for running the app in a container)

## Getting Started

1. Clone the repository:

```sh
git clone https://github.com/github-community-projects/private-mirrors.git
cd private-mirrors
```

2. Install the dependencies:

```sh
npm install
```

3. Create a `.env` file in the root of the repository and add the necessary environment variables. Use the `.env.example` file as a reference.

4. Run the development server:

```sh
npm run dev
```

The app should now be running on `http://localhost:3000`.

## GitHub App

To use the app, you'll need to create a GitHub App and configure it to point to your local development environment.

1. Go to your Organization's profile, **Settings**, and select **GitHub Apps**.
2. Fill in the required fields:
- **GitHub App name**: Private Mirrors App (or any name you prefer)
- **Homepage URL**: `http://localhost:3000`
- **Webhook URL**: `http://localhost:3000/api/webhooks`
- **Webhook secret**: Generate a random secret and add it to your `.env` file as `WEBHOOK_SECRET`
3. Under **Repository permissions**, set the following permissions:
- **Actions**: Read and write
- **Administration**: Read and write
- **Contents**: Read and write
- **Custom Properties**: Read and write
- **Workflows**: Read and write
4. Under **Organization permissions**, set the following permissions:
- **Custom properties**: Admin
- **Members**: Read and write
5. Under **Account permissions**, set the following permissions:

- **Email addresses**: Read-only

6. Under **Subscribe to events**, select the following events:

- **Installation target**
- **Meta**
- **Branch protection rule**
- **Fork**
- **Public**
- **Push**
- **Repository**
- **Repository dispatch**
- **Workflow dispatch**
- **Workflow job**
- **Workflow run**

7. Click **Create GitHub App**.
8. Generate a private key for the app and add it to your `.env` file as `PRIVATE_KEY`.
9. Note the **App ID** and **Client ID** and add them to your `.env` file as `APP_ID` and `GITHUB_CLIENT_ID`, respectively.
10. Generate a new **Client Secret** and add it to your `.env` file as `GITHUB_CLIENT_SECRET`.

## Running the App with Docker

If you prefer to run the app in a Docker container, follow these steps:

1. Pull the docker image from the GitHub Container Registry:

```sh
docker pull ghcr.io/github-community-projects/private-mirrors:latest
```

Or, if you prefer to make your own, build the Docker image:

```sh
docker build -t private-mirrors .
```

2. Run the Docker container:

```sh
docker run --env-file=.env -p 3000:3000 private-mirrors
```

The app should now be running on `http://localhost:3000`.

## Testing

To run the tests, use the following command:

```sh
npm test
```

This will run the test suite and display the results in the terminal.

## Linting

To check for linting errors, use the following command:

```sh
npm run lint
```

This will run ESLint and display any linting errors in the terminal.

## Building

To build the app for production, use the following command:

```sh
npm run build
```

This will create an optimized production build of the app in the `out` directory.

## Deployment

To deploy the app, follow the instructions for your preferred hosting provider. The app can be deployed to any hosting provider that supports Next.js/Docker.
Loading