Skip to content

marketplace.packages[].source: generalize beyond host/owner/repo (deeply-nested GitLab subgroups, arbitrary git hosts) #1519

Description

Summary

PR #1288 (merged) extended marketplace.packages[].source to accept <host.tld>/<owner>/<repo> and https://<host.tld>/<owner>/<repo>[.git]. That unblocks GitHub Enterprise and shallow GitLab layouts, but the regex pins exactly three path segments (host + owner + repo), and the test suite explicitly rejects 4+ segments (test_four_segment_path_rejected).

Self-hosted GitLab deployments commonly nest projects under multiple subgroups, e.g.:

gitlab.example.com/group/sub-group/team/projects/my-package

That's host + 4 path segments + repo. With the post-#1288 schema there is still no source form that names this repo — the schema rejects every URL form, the git: { url: ... } object form is rejected as "must be a non-empty string", and the bare <owner>/<repo> shorthand silently routes to github.com regardless of marketplace.owner.url. The apm view resolver, by contrast, already handles arbitrary-depth host-prefixed paths correctly — so this is a marketplace-schema gap, not a resolver-capability gap.

Repro

apm.yml:

name: test-mp
version: 0.1.0
description: repro
marketplace:
  owner:
    name: my-group
    url: https://gitlab.example.com/group/sub-group/team/projects
  outputs:
    claude: {}
  build:
    tagPattern: "v{version}"
  packages:
    - name: my-package
      description: deeply nested repo
      source: gitlab.example.com/group/sub-group/team/projects/my-package
      version: "^0.1.0"
$ apm marketplace check
[x] marketplace config error: 'packages[0].source' must be one of
    '<owner>/<repo>', '<host.tld>/<owner>/<repo>',
    'https://<host.tld>/<owner>/<repo>[.git]', or './<path>',
    got 'gitlab.example.com/group/sub-group/team/projects/my-package'

The object form sometimes recommended in authoring guides also fails:

      source:
        git: https://gitlab.example.com/group/sub-group/team/projects/my-package.git
[x] marketplace config error: 'packages[0].source' must be a non-empty string

Evidence the resolver itself isn't the blocker

$ apm view gitlab.example.com/group/sub-group/team/projects/my-package versions
Available versions:
  v0.1.0    tag      5d908cad
  main      branch   5d908cad

Evidence marketplace.owner.url is unused at resolution time

With:

marketplace:
  owner:
    url: https://gitlab.example.com/group/sub-group/team/projects
  packages:
    - source: my-group/my-package          # the only schema-accepted shorthand

I wrapped git on PATH to log every invocation. apm marketplace check ran:

git ls-remote --tags --heads https://github.com/my-group/my-package.git

The shorthand routed to github.com, ignoring owner.url. That's consistent with the schema docs (§7.3): owner.url is documented as "Owner homepage" — descriptive metadata, not a resolution input.

Why this matters

Self-hosted GitLab with subgroup nesting is the canonical enterprise pattern in many orgs. Until the schema accepts a form that names these repos, APM marketplaces can't list them — and the only schema-accepted shorthand silently exfiltrates the lookup to github.com under whatever auth happens to be in scope, which is also a small footgun for anyone publishing a marketplace from an enterprise tenant.

Suggested directions

Two options, not mutually exclusive:

Option A (preferred): a marketplace-level git base, packages name themselves relative to it

This is the shape every other package manager has converged on — npm's registry, cargo's [registries], Maven's <repositories>. Declare the host/path once, then entries don't repeat it. It sidesteps the "how many slashes" parser problem entirely.

A new field is cleaner than repurposing owner.url (which is documented as "Owner homepage" and the official example, https://github.com/contoso, is a profile page with no git semantics):

marketplace:
  sourceBase: https://gitlab.example.com/group/sub-group/team/projects
  owner:
    name: my-group
    url: https://gitlab.example.com/groups/group/sub-group/team/projects   # still a homepage
  packages:
    - name: my-package
      source: my-package                             # → sourceBase + my-package

    - name: external
      source: github.com/some-org/external           # #1288's host-prefixed form
                                                      # overrides sourceBase

Properties:

(Field name sourceBase is illustrative — host, defaultHost, registry, etc. are all reasonable.)

Option B (mechanical fallback): widen the source regex to accept >3 path segments

Treat the last two slash-separated segments as owner/repo, everything before as host + group path. Same security guards from #1288 (no userinfo, no port, no query, https-only for URL form). Less elegant than Option A but a smaller diff if sourceBase is too big a change to land soon.

These compose well — Option A is the principled fix, Option B is available for one-off packages that don't fit the marketplace's base.

Decision needed from maintainers

Before anyone invests in implementation, it would help to know which direction lands cleanly with your design intent for the marketplace block:

  • Option A only — introduce a marketplace-level base field; keep the source regex as-is.
  • Option B only — widen the source regex to arbitrary depth; don't introduce a new field.
  • Both — Option A as the primary path, Option B as the per-package escape hatch (my read of the trade-offs, but happy to be redirected).
  • Neither / different shape — there's a direction we haven't considered.

Once a direction is chosen I'm happy to take a stab at the implementation PR (schema + tests + docs), tested against an actual deeply-nested self-hosted GitLab on our side. Just need the maintainer steer first to avoid building the wrong thing.

Out of scope (suggested for separate issues)

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area/enterpriseAir-gapped/GHE configurability, registry proxy, rulesets, adoption playbook.area/marketplacemarketplace.json schema, federation, authoring suite, source parity.priority/highHuman-set high priority; not scope approval, a release commitment or a required milestone.status/acceptedHuman scope approval; verify the issue's approval record and review contact before work.status/shepherdingActively being driven by an APM shepherd runstatus/triagedAutomated advice completed; deduplication only. Not human approval; silence is not approval.theme/governanceGoverned by policy. apm-policy, audit, enforcement, enterprise rollout.type/featureNew capability, new flag, new primitive.

Type

No type

Projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions