---
sidebar_label: Init container (removed in 3.0.0)
toc_max_heading_level: 3
doc_id: e7a3f1d2-8b94-4c6a-9e7d-2f5c8d4a1b30
description: >-
  The githubTokenInit init container was removed in nullplatform-agent chart
  3.0.0. Kept for reference on chart 2.x; use github.apps instead.
keywords:
  - github app
  - private repos
  - agent installation
  - helm
  - kubernetes
  - nullplatform agent
---

# Authenticate private repos with a GitHub App (removed)

:::danger Removed in chart 3.0.0
`githubTokenInit` was removed from the `nullplatform-agent` Helm chart in **version 3.0.0**, released on September 1, 2026. A release that still sets it won't render: the chart aborts with an error pointing you at `github.apps`.

The init container minted one token at pod startup and never renewed it, and it supported a single installation ID. The agent now mints per-org installation tokens itself and renews them before they expire. See [GitHub App auth for agent repos](github-app-command-repos.md) for the supported setup.

This page is kept for reference if you're still on chart 2.x. Everything below applies only to those versions.
:::

When the agent reads scopes and actions from a **private GitHub repository**, chart 2.x can use a GitHub App to authenticate instead of embedding a personal access token in `AGENT_REPO`.

## When to use this

The basic [Helm install](install-helm.md) authenticates the agent repo via a token embedded in the URL:

```bash
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.

```mermaid
flowchart LR
    A["**GitHub App credentials**<br/>Kubernetes Secret with App ID,<br/>Installation ID, private key"]
    B["**Init container**<br/>Builds a JWT from the private key.<br/>Exchanges it for a short-lived<br/>installation token. Clones the<br/>private repo into a shared volume."]
    C["**Agent container**<br/>Reads the cloned repo from the<br/>shared volume and connects to<br/>nullplatform."]

    A -- "reads" --> B
    B -- "shared volume" --> C

    classDef customer fill:#eef3fb,stroke:#274a86,color:#0b1e3f,stroke-width:1.5px;
    class A,B,C customer;

    linkStyle 0 stroke:#0b1e3f,stroke-width:2.5px;
    linkStyle 1 stroke:#0b1e3f,stroke-width:2.5px;
```

> 🔒 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](install-helm.md)).
- A nullplatform API key with the **agent** and **ops** roles. See [Authenticate the agent](authentication.md).
- 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](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-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:

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

Then pass all three credentials when you install the chart:

```bash
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`):

```yaml
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:

```bash
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:

```bash
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.

| Value | Default | What it does |
| --- | --- | --- |
| `enabled` | `false` | Adds 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` |
| `secretName` | `github-app-secret` | Name of the Kubernetes Secret holding the App credentials |
| `secretKeys.appId` | `APP_ID` | Key inside the Secret for the App ID |
| `secretKeys.installationId` | `INSTALLATION_ID` | Key inside the Secret for the Installation ID |
| `secretKeys.privateKey` | `PRIVATE_KEY` | Key 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/.np` | Shared volume mount path. Must match the agent's command executor base path |
| `image` | `alpine:3.22.2` | Init 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:

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

With this init container flow, the agent container has no credentials of its own, so **Refresh sources** from the UI can't re-clone the repo. Treat pod restarts as the way to update the code the agent runs.

This is one of the reasons the init container was removed. On chart 3.0.0 and later, configure [GitHub App auth for agent repos](github-app-command-repos.md): the agent mints its own installation tokens, so **Refresh sources** works normally and no restart is needed.

## Next step

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

[Create a notification channel →](agent-channel.md)
