lenshq/github
Clone, push, and work with repositories, issues, pull requests, and packages on GitHub.
GitHub connector
Lets a workload clone, push, call the API and install packages without the token ever entering the sandbox.
lns connector install lenshq/github
What it serves
Seven hosts, because GitHub spreads one token across seven:
| Host | For |
|---|---|
github.com | git clone and git push over HTTPS |
api.github.com | the REST and GraphQL API, which gh calls |
codeload.github.com | tarball and zipball downloads |
uploads.github.com | release asset uploads |
objects.githubusercontent.com | release assets and LFS objects |
npm.pkg.github.com | the npm package registry |
maven.pkg.github.com | the maven package registry |
The list is deliberately broad. A destination it misses is one the connector is never offered for, so a narrow list means a clone that fails with no card to answer. One card answers for all seven.
How you sign in
Two methods. Pick either when lns asks.
GitHub account — sign in with a code. lns shows a short code, you enter it at https://github.com/login/device, and GitHub hands the token back. No browser needs to reach this machine, so it works over SSH and on a headless host.
Personal access token — create a classic token at
https://github.com/settings/tokens with repo, read:org and
read:packages, then paste it.
Device flow is the browser route here rather than a redirect because GitHub's authorization-code exchange requires a client secret, and the document format refuses secrets outright.
Note what read-only means. GitHub's classic scopes have no read-only variant for private repositories, so the read-only option covers your profile, your organisations, public repositories and package reads. Cloning a private repository needs read and write.
What the workload sees
| Variable | Value |
|---|---|
GH_TOKEN | A placeholder, never the token. |
GH_TOKEN is what the gh CLI reads, and git authenticates through the same
injections, so both work with no extra configuration.
The value is a marker. lns swaps the real token in on the way out, host by host, and the form differs per host because GitHub does not accept one form everywhere:
| Host | Header lns sets |
|---|---|
github.com, codeload.github.com | HTTP Basic as x-access-token:<token> — what git sends |
api.github.com, uploads.github.com | Authorization: token <token> |
npm.pkg.github.com, maven.pkg.github.com | Authorization: Bearer <token> |
objects.githubusercontent.com | none, deliberately |
That last row matters. A release asset and an LFS object arrive as a pre-signed
URL, and a second Authorization header makes the object store refuse the
request. So that host gets egress and nothing else.
A request the workload sends to any other host carries no GitHub token, even if the workload copies the variable there itself. The variable is lent to a sandbox that declares it, so a sandbox asking for nothing receives nothing.
SSH is not covered
github.com is served on every port, including 22, but a grant opens nothing
there. This connector declares no raw-TCP rules, so an SSH stream is spliced
through unread — no header and no placeholder reaches it. SSH authenticates with
a key, and no token substitutes for one. Clone over HTTPS, or bring your own
key.
Two hosts left out on purpose
ghcr.ioauthenticates with its own token exchange, so it belongs to its own connector. Claiming it here would refuse that connector's install, because two installed connectors may not serve one destination.raw.githubusercontent.comis usually reached unauthenticated. A destination a policy sends direct is never read by the proxy, and an injection the proxy cannot apply is a card that grants nothing.
What it grants
Only the seven hosts above, and only after you connect. Installing the connector grants nothing on its own: it opens no destination, sets no variable and arms no injection. It makes those destinations ask, and a grant belongs to one run.
A pasted token's scope is its own business — lns does not narrow a token it was handed. Signing in with a code is the narrower option, because the scope you pick is the scope GitHub issues.
One caveat on the package registries: their entry here is not always enough on
its own, because a run's own decisions resolve after a grant. A sandbox that
installs from npm.pkg.github.com during its build should state that host
itself rather than rely on the card.
Specification
Serves
github.comapi.github.comcodeload.github.comobjects.githubusercontent.comuploads.github.comnpm.pkg.github.commaven.pkg.github.comReaching one of these makes a run ask about this connector. Installing it opens nothing on its own.
2 methods
Alternatives, in the author's order of preference. A run grants one, and only that method's payload applies.
deviceSign in with a code shown here and entered at github.com/login/device.Opens on a grant
| Protocol | Destination | Verdict |
|---|---|---|
http | github.com | allow |
http | api.github.com | allow |
http | codeload.github.com | allow |
http | uploads.github.com | allow |
http | objects.githubusercontent.com | allow |
http | npm.pkg.github.com | allow |
http | maven.pkg.github.com | allow |
Credentials
| Variable | Placeholder | Injected into |
|---|---|---|
GH_TOKEN | gho_LNSPLACEHOLDER0000000000000000000000 | basic auth → github.combasic auth → codeload.github.comtoken header → api.github.comtoken header → uploads.github.combearer header → npm.pkg.github.combearer header → maven.pkg.github.com |
tokenCreate a classic token at github.com/settings/tokens with repo, read:org and read:packages scope.Opens on a grant
| Protocol | Destination | Verdict |
|---|---|---|
http | github.com | allow |
http | api.github.com | allow |
http | codeload.github.com | allow |
http | uploads.github.com | allow |
http | objects.githubusercontent.com | allow |
http | npm.pkg.github.com | allow |
http | maven.pkg.github.com | allow |
Credentials
| Variable | Placeholder | Injected into |
|---|---|---|
GH_TOKEN | gho_LNSPLACEHOLDER0000000000000000000000 | basic auth → github.combasic auth → codeload.github.comtoken header → api.github.comtoken header → uploads.github.combearer header → npm.pkg.github.combearer header → maven.pkg.github.com |