MemberJunction / MemberJunction/MJ

mj app install: a private Open App repo reports "Tag 'vX.Y.Z' not found" when the real cause is missing GitHub auth

Open
#4,505 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
TSQL
Stars
29
Forks
6
Avg merge
2d 1h
Merged PRs (30d)
323

Description

## Summary

`mj app install` against a **private** Open App repository fails with a message that blames a missing tag, when the tag exists and the real cause is that no GitHub credential was supplied. The message then points at the repo's `/tags` page — which a signed-in maintainer opens and sees the tag on, confirming the wrong conclusion.

GitHub returns **404, not 403**, for a private repository the caller cannot see. So "tag missing" and "repo not visible to this credential" arrive identically, and the installer reports only the first.

## Reproduction

Against any private Open App repo with a valid release tag (here `MemberJunction/bizapps-ats`, tag `v6.0.0`), with no `GITHUB_TOKEN` in the environment:

```
mj app install https://github.com/MemberJunction/bizapps-ats --version 6.0.0 --non-interactive --verbose
```

```
- [Fetch] Validating version tag v6.0.0 exists...
GET /repos/MemberJunction/bizapps-ats/git/ref/tags%2Fv6.0.0 - 404
✖ Install failed: Tag 'v6.0.0' not found in MemberJunction/bizapps-ats.
Available versions can be checked at https://github.com/MemberJunction/bizapps-ats/tags
```

The tag does exist. Same API call, unauthenticated vs authenticated:

| Call | Result |
|---|---|
| Unauthenticated `GET /repos/.../git/ref/tags/v6.0.0` | **404** |
| Authenticated with a repo-scoped token | **200** → `refs/tags/v6.0.0` |

`git ls-remote --tags https://github.com/MemberJunction/bizapps-ats` also lists `v6.0.0`, because local git credentials are configured — which makes the CLI's report look even more like a genuine missing tag.

Re-running the identical command with `GITHUB_TOKEN=$(gh auth token)` proceeds past tag validation, fetches the manifest, and resolves the dependency graph.

## Root cause

`packages/OpenApp/Engine/src/github/github-client.ts` → `ValidateGitHubTag` (~L722):

```ts
catch (error: unknown) {
if (OctokitStatus(error) === 404) {
return { Exists: false, ErrorMessage: `Tag '${tag}' not found in ${parsed.Owner}/${parsed.Repo}. Available versions can be checked at ${repoUrl}/tags` };
}
```

A 404 is attributed unconditionally to the tag. For a private repo without credentials the 404 is the *repository*, not the ref.

## Why it is worth fixing rather than documenting

The token is already supported — `packages/MJCLI/src/utils/open-app-context.ts:259` reads `config.openApps?.github?.token ?? process.env.GITHUB_TOKEN`. But `mj app install --help` documents only `--version`, `-v` and `--non-interactive`, so nothing in the command's own surface connects the failure to the remedy. Every first-party BizApp repo is private, so this is the first thing a maintainer hits.

## Suggested fix

Distinguish the two cases before composing the message. On a 404 during tag validation, probe repo visibility (`GET /repos/{owner}/{repo}`) and, when *that* also 404s with no credential present, say so — naming `GITHUB_TOKEN` / `openApps.github.token`. Something like:

> Cannot read `MemberJunction/bizapps-ats`. The repository is private or does not exist, and no GitHub credential was supplied — set `GITHUB_TOKEN` or `openApps.github.token` in `mj.config.cjs`.

Documenting `GITHUB_TOKEN` in `mj app install --help` would help independently of the message change.

## Environment

`@memberjunction/cli` 6.1.0, macOS, Node 24.20.0. Found while doing a clean-room `mj app install` of a newly published private Open App.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Contributor guide

Open the contributing guide

Research direction

Start in packages/OpenApp/Engine/src/github/github-client.ts at ValidateGitHubTag, then inspect the token lookup in packages/MJCLI/src/utils/open-app-context.ts. Reproduce the shown private-repository install without GITHUB_TOKEN and compare it with an authenticated run. Done means a 404 caused by missing repository access produces an actionable credential message instead of claiming the tag is missing.

Written by the indexing model from the issue text.

Assessment

Tech stack
github, node.js, typescript
Domain
api, authentication, cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
74/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.