Skip to main content

Authenticate private repos with a GitHub App

When the agent reads scopes and actions from a private GitHub repository, the Helm chart can use a GitHub App to authenticate instead of embedding a personal access token in AGENT_REPO. This is the recommended pattern for production.

When to use this

The basic Helm install authenticates the agent repo via a token embedded in the URL:

AGENT_REPO="https://<git-token>@github.com/your-org/private-repo.git#main"

That works, but personal access tokens are long-lived, tied to a user account, and easy to leak via Helm history or kubectl describe pod. The GitHub App flow avoids both problems:

  • Short-lived credentials. Each pod start generates a fresh installation token (valid for one hour).
  • No personal account dependency. The App belongs to your GitHub organization, not to an individual.
  • Fine-grained permissions. You grant the App access only to the specific repos the agent needs.

How it works

When the chart is deployed with githubTokenInit.enabled=true, the agent pod runs an init container before the agent itself starts. The init container reads GitHub App credentials from a Kubernetes Secret, exchanges them for a short-lived token, and clones the repo into a shared volume that the agent container then reads.

🔒 The GitHub App private key never leaves the cluster. The init container generates the JWT locally and only the resulting installation token reaches GitHub.

Prerequisites

  • A Kubernetes cluster and Helm 3+ (same as the base Helm install).
  • A nullplatform API key with the agent and ops roles. See Authenticate the agent.
  • A GitHub App installed on the organization that owns the agent repo, with read access to the repos you want to clone.

1. Set up the GitHub App

In your GitHub organization, create a new GitHub App with the following:

  • Repository permissions: Contents: Read-only, Metadata: Read-only.
  • A new private key (download the .pem file when GitHub shows it; you can't retrieve it later).

Then install the App on your organization and select the agent repo. After installation, note down:

  • The App ID (visible on the App's settings page).
  • The Installation ID (the numeric ID at the end of the URL after you install the App).
  • The contents of the private key .pem file.

2. Provide the credentials to the chart

The chart supports two patterns. Pick the one that fits your secrets workflow.

Option A: Chart-managed secret

The chart creates the Kubernetes Secret for you from values you pass via --set. This is the simplest option for development or single-team installs.

The private key value must be base64-encoded. Generate it from your .pem file:

export PRIVATE_KEY_B64=$(base64 -w 0 < path/to/private-key.pem)

Then pass all three credentials when you install the chart:

helm install nullplatform-agent nullplatform/nullplatform-agent \
--namespace nullplatform-tools --create-namespace \
--set githubTokenInit.enabled=true \
--set githubTokenInit.repositoryUrl=github.com/your-org/private-repo.git \
--set githubTokenInit.values.appId=<your_app_id> \
--set githubTokenInit.values.installationId=<your_installation_id> \
--set githubTokenInit.values.privateKey=$PRIVATE_KEY_B64 \
--set configuration.values.NP_API_KEY=$NP_API_KEY \
--set configuration.values.TAGS="$AGENT_TAGS"

The chart creates a Secret named github-app-secret and wires the init container to read from it.

Option B: Bring your own secret

For production or GitOps workflows, you typically manage Secrets through a tool like External Secrets Operator or sealed-secrets. In that case, pre-create the Secret yourself and point the chart at it.

Create a Secret with these three keys (default names: APP_ID, INSTALLATION_ID, PRIVATE_KEY):

apiVersion: v1
kind: Secret
metadata:
name: github-app-secret
namespace: nullplatform-tools
type: Opaque
stringData:
APP_ID: "<your_app_id>"
INSTALLATION_ID: "<your_installation_id>"
PRIVATE_KEY: "<base64-encoded private key PEM>"

Then install the chart referencing the existing Secret:

helm install nullplatform-agent nullplatform/nullplatform-agent \
--namespace nullplatform-tools --create-namespace \
--set githubTokenInit.enabled=true \
--set githubTokenInit.repositoryUrl=github.com/your-org/private-repo.git \
--set githubTokenInit.secretName=github-app-secret \
--set configuration.values.NP_API_KEY=$NP_API_KEY \
--set configuration.values.TAGS="$AGENT_TAGS"

Override githubTokenInit.secretKeys.* if you use different key names in your Secret.

3. Verify the init container ran

Once the chart is installed, check the init container logs to confirm the clone succeeded:

kubectl logs -n nullplatform-tools <agent-pod-name> -c github-token-init

You should see the token request to GitHub and the repo clone output. If the agent pod is Running, the agent container is connected and the cloned repo is mounted at /root/.np/<repo-name>.

Then verify the agent appears in the platform UI under Platform settings > Agents.

Configuration reference

All values live under githubTokenInit in the chart values.

ValueDefaultWhat it does
enabledfalseAdds the init container that authenticates with GitHub and clones the repo
repositoryUrl""Repo URL to clone. Omit the https:// prefix (the init container prepends it with the token). Example: github.com/your-org/private-repo.git
secretNamegithub-app-secretName of the Kubernetes Secret holding the App credentials
secretKeys.appIdAPP_IDKey inside the Secret for the App ID
secretKeys.installationIdINSTALLATION_IDKey inside the Secret for the Installation ID
secretKeys.privateKeyPRIVATE_KEYKey inside the Secret for the base64-encoded private key
values.appId""App ID, when letting the chart create the Secret (Option A)
values.installationId""Installation ID, when letting the chart create the Secret (Option A)
values.privateKey""Base64-encoded PEM, when letting the chart create the Secret (Option A)
workingDir/root/.npShared volume mount path. Must match the agent's command executor base path
imagealpine:3.22.2Init container image. Must include apk

Refreshing the cloned repo

The init container runs only at pod startup. To pull new commits from the agent repo after the pod is running, restart the agent so the init container runs again with a fresh token:

kubectl rollout restart deployment/nullplatform-agent-<release-name> -n nullplatform-tools

The refresh-sources command from the platform UI only works when the agent has its own clone credentials configured via AGENT_REPO. With GitHub App auth, treat pod restarts as the way to update the code the agent runs.

Next step

Once the agent is installed and registered, create a notification channel so it can respond to platform events.

Create a notification channel →