Skip to content

fix(claude): preserve marketplace source shape for allowlist matching#345

Merged
dpup merged 1 commit into
majorcontext:mainfrom
abezzub-dr:fix/claude-marketplace-source-shape
May 18, 2026
Merged

fix(claude): preserve marketplace source shape for allowlist matching#345
dpup merged 1 commit into
majorcontext:mainfrom
abezzub-dr:fix/claude-marketplace-source-shape

Conversation

@abezzub-dr
Copy link
Copy Markdown
Contributor

@abezzub-dr abezzub-dr commented Apr 28, 2026

Summary

  • Stop normalizing {source: github, repo: X} marketplace entries to {source: git, url: https://github.com/X.git} in LoadSettings, LoadKnownMarketplaces, and ConfigToSettings. Pass the original source shape through to the container.
  • Update the marketplace extraction loop in internal/run/manager.go to handle both {Source: github, Repo} and {Source: git, URL} entries when populating MarketplaceConfig.
  • Update tests that locked in the old normalized output.

Why

When a host's ~/.claude/remote-settings.json declares strictKnownMarketplaces — an exact-match allowlist of {source, repo|url} pairs that moat copies into the container (#306) — the normalized form no longer matched the shape the host was registered with. Claude Code inside the container rejected every plugin install with Marketplace "X" is not in the allowed marketplace list, even though plain claude on the host worked because its known_marketplaces.json registration matched the allowlist's github+repo entry.

Concretely, the bug path:

  1. LoadSettings rewrote {source: github, repo: company-name/claude-marketplace}{source: git, url: https://github.com/digitalroute/dr-claude-marketplace.git}.
  2. manager.go then stripped the URL back to company-name/claude-marketplace for MarketplaceConfig.Repo, but kept Source: "git".
  3. GenerateKnownMarketplaces saw Source == "git" and wrote {source: git, url: "company-name/claude-marketplace"} into the container's known_marketplaces.json — a path stuffed into a URL field, matching neither allowlist entry.

Preserving the original shape end-to-end avoids the lossy conversion entirely. Downstream consumers (GenerateKnownMarketplaces, CloneMarketplace, claude plugin marketplace add) already accept either form, so no further changes were needed.

Test plan

  • go test -race ./... — full suite green
  • go vet ./internal/providers/claude/... ./internal/run/... — clean
  • gofmt -l — clean on changed files
  • Manual test: run moat claude in a project whose host ~/.claude/remote-settings.json contains strictKnownMarketplaces and confirm plugins install without "not in the allowed marketplace list" errors
  • Manual test: confirm moat claude still works for users without strictKnownMarketplaces (no regression for the unconstrained path)

Marketplace entries like {source: github, repo: owner/repo} were being
rewritten to {source: git, url: https://github.com/owner/repo.git} in
LoadSettings, LoadKnownMarketplaces, and ConfigToSettings before being
written into the container's settings.json and known_marketplaces.json.

When a host ~/.claude/remote-settings.json declares strictKnownMarketplaces
(an exact-match allowlist of {source, repo|url} pairs that moat copies
into the container), the normalized form no longer matched the shape the
host had registered with, so Claude Code inside the container rejected
every plugin install with "Marketplace ... is not in the allowed
marketplace list" — even though plain `claude` on the host worked.

Stop normalizing at those three sites and pass the original source shape
through. Update the manager.go extraction loop to switch on
entry.Source.Source and copy either Repo (github) or URL (git) into
MarketplaceConfig.Repo. Downstream consumers (GenerateKnownMarketplaces,
CloneMarketplace, `claude plugin marketplace add`) already accept either
form, so no changes are needed there.

Update existing tests that locked in the old normalized output to assert
the preserved shape.
@abezzub-dr abezzub-dr force-pushed the fix/claude-marketplace-source-shape branch from 7b5e60f to cd49a37 Compare May 18, 2026 08:05
@abezzub-dr
Copy link
Copy Markdown
Contributor Author

@dpup any thoughts on this PR?

remote-settings.json for our org has the following:

  "strictKnownMarketplaces": [
    {
      "repo": "company-name/claude-marketplace",
      "source": "github"
    },
    {
      "source": "git",
      "url": "https://github.com/company-name/claude-marketplace.git"
    }
  ]

Without this PR moat produces invalid known_marketplaces.json entry (see below), so our employer marketplace cannot be loaded.

    {
      "source": "git",
      "url": "company-name/claude-marketplace"
    },

@dpup dpup merged commit 4568fc8 into majorcontext:main May 18, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants