Skip to content

Commit 5baa7e4

Browse files
akoclaude
andcommitted
fix: point auth host map at real Mendix platform hosts
Spike confirmed the documented "Authorization: MxToken <pat>" scheme works against marketplace-api.mendix.com (not appstore.home.mendix.com as earlier docs and the marketplace proposal claimed) and also works against catalog.mendix.com. appstore.home.mendix.com is a different service that does not accept PAT auth at all. Updates hostSchemes to the two confirmed hosts and refocuses the discovery spike script on endpoint-path mapping now that the auth question is settled. Next spike run will tell us the shape of /v1/content responses so we can design the marketplace package. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2f291c9 commit 5baa7e4

3 files changed

Lines changed: 145 additions & 6 deletions

File tree

internal/auth/client_test.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func TestAuthTransport_InjectsPATHeader(t *testing.T) {
4444
}
4545

4646
// Use a known Mendix host so the scheme lookup succeeds.
47-
resp, err := client.Get("https://appstore.home.mendix.com/rest/packagesapi/v2/packages/2888")
47+
resp, err := client.Get("https://marketplace-api.mendix.com/v1/content/2888")
4848
if err != nil {
4949
t.Fatalf("request: %v", err)
5050
}
@@ -81,7 +81,7 @@ func TestAuthTransport_401WrapsAsUnauthenticated(t *testing.T) {
8181
},
8282
}
8383

84-
resp, err := client.Get("https://appstore.home.mendix.com/foo")
84+
resp, err := client.Get("https://marketplace-api.mendix.com/foo")
8585
if resp != nil {
8686
resp.Body.Close()
8787
}
@@ -107,7 +107,7 @@ func TestAuthTransport_DoesNotMutateCallerRequest(t *testing.T) {
107107
inner: &rewriteTransport{target: target, inner: http.DefaultTransport},
108108
}
109109

110-
req, _ := http.NewRequest("GET", "https://appstore.home.mendix.com/foo", nil)
110+
req, _ := http.NewRequest("GET", "https://marketplace-api.mendix.com/foo", nil)
111111
if _, err := tr.RoundTrip(req); err != nil {
112112
t.Fatalf("roundtrip: %v", err)
113113
}
@@ -178,8 +178,11 @@ func contains(s, sub string) bool {
178178
}
179179

180180
func TestSchemeForHost(t *testing.T) {
181-
if s, ok := SchemeForHost("appstore.home.mendix.com"); !ok || s != SchemePAT {
182-
t.Errorf("appstore host should map to PAT, got (%q, %v)", s, ok)
181+
if s, ok := SchemeForHost("marketplace-api.mendix.com"); !ok || s != SchemePAT {
182+
t.Errorf("marketplace-api host should map to PAT, got (%q, %v)", s, ok)
183+
}
184+
if s, ok := SchemeForHost("catalog.mendix.com"); !ok || s != SchemePAT {
185+
t.Errorf("catalog host should map to PAT, got (%q, %v)", s, ok)
183186
}
184187
if _, ok := SchemeForHost("evil.example.com"); ok {
185188
t.Errorf("unknown host should return false")

internal/auth/scheme.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,15 @@ package auth
77
// Add a host here when wiring a new platform API consumer. If a request
88
// targets an unlisted host, the client returns an error rather than silently
99
// sending a token to the wrong service.
10+
//
11+
// Hosts validated against real PATs during the auth discovery spike
12+
// (2026-04): marketplace-api.mendix.com and catalog.mendix.com both accept
13+
// the documented "Authorization: MxToken <pat>" header. The older
14+
// appstore.home.mendix.com that earlier docs pointed at is a different
15+
// service and does not accept PAT auth — do not add it here.
1016
var hostSchemes = map[string]Scheme{
11-
"appstore.home.mendix.com": SchemePAT,
17+
"marketplace-api.mendix.com": SchemePAT,
18+
"catalog.mendix.com": SchemePAT,
1219
}
1320

1421
// SchemeForHost returns the auth scheme required by the given hostname.

scripts/auth-discovery-spike.sh

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#!/usr/bin/env bash
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
# auth-discovery-spike.sh — Map the Mendix Marketplace API surface.
5+
#
6+
# Round-3 scope. We have already confirmed (round 2) that PAT via
7+
# "Authorization: MxToken <pat>" works against marketplace-api.mendix.com.
8+
# This round discovers endpoint paths and response shapes so we can design
9+
# the marketplace package.
10+
#
11+
# Reads $MENDIX_PAT from the environment; never logs it.
12+
# Output: /tmp/auth-spike-report.md (redacted — safe to share).
13+
#
14+
# Usage:
15+
# export MENDIX_PAT='<your-pat>' # create at https://user-settings.mendix.com/
16+
# ./scripts/auth-discovery-spike.sh
17+
# cat /tmp/auth-spike-report.md
18+
19+
set -u
20+
21+
REPORT=/tmp/auth-spike-report.md
22+
MARKETPLACE="https://marketplace-api.mendix.com"
23+
CATALOG="https://catalog.mendix.com"
24+
25+
if [[ -z "${MENDIX_PAT:-}" ]]; then
26+
echo "error: MENDIX_PAT is not set" >&2
27+
echo "create a PAT at https://user-settings.mendix.com/ and export it:" >&2
28+
echo " export MENDIX_PAT='...'" >&2
29+
exit 2
30+
fi
31+
32+
# Redact the PAT from any output we write to the report.
33+
redact() {
34+
sed "s|${MENDIX_PAT}|MENDIX_PAT_REDACTED|g"
35+
}
36+
37+
# probe <label> <method> <url> [curl args...]
38+
probe() {
39+
local label="$1"
40+
local method="$2"
41+
local url="$3"
42+
shift 3
43+
44+
local tmp_body tmp_headers code
45+
tmp_body=$(mktemp)
46+
tmp_headers=$(mktemp)
47+
code=$(curl -sS -o "$tmp_body" -D "$tmp_headers" -w "%{http_code}" \
48+
-X "$method" \
49+
-H "Authorization: MxToken $MENDIX_PAT" \
50+
-H "Accept: application/json" \
51+
"$@" \
52+
"$url" 2>&1) || code="CURL_ERR"
53+
54+
echo "### $label"
55+
echo
56+
echo '```'
57+
echo "$method $url"
58+
echo "HTTP $code"
59+
echo "--- response headers ---"
60+
head -20 "$tmp_headers" | redact
61+
echo "--- response body (first 60 lines) ---"
62+
head -60 "$tmp_body" | redact
63+
echo '```'
64+
echo
65+
66+
rm -f "$tmp_body" "$tmp_headers"
67+
}
68+
69+
{
70+
echo "# Marketplace API Spike Report"
71+
echo
72+
echo "Generated: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
73+
echo "Marketplace base: \`$MARKETPLACE\`"
74+
echo "Catalog base: \`$CATALOG\`"
75+
echo "Auth scheme: \`Authorization: MxToken <pat>\`"
76+
echo
77+
echo "PAT is redacted as \`MENDIX_PAT_REDACTED\`. Safe to share."
78+
echo
79+
80+
echo "## Marketplace API — endpoint discovery"
81+
echo
82+
echo "Known working: \`GET /v1/content\`. Map out the rest of the surface."
83+
echo
84+
85+
probe "GET /v1/content (known working)" GET "$MARKETPLACE/v1/content?limit=3"
86+
probe "GET /v1/content/2888 (component detail — DB Connector)" \
87+
GET "$MARKETPLACE/v1/content/2888"
88+
probe "GET /v1/content?search=database" GET "$MARKETPLACE/v1/content?search=database&limit=3"
89+
probe "GET /v1/content/2888/versions" GET "$MARKETPLACE/v1/content/2888/versions"
90+
probe "GET /v1/content/2888/releases" GET "$MARKETPLACE/v1/content/2888/releases"
91+
probe "GET /v1 (index — hope for hypermedia)" \
92+
GET "$MARKETPLACE/v1"
93+
probe "GET / (root — hope for hypermedia)" GET "$MARKETPLACE/"
94+
95+
echo "## Catalog API — sanity check"
96+
echo
97+
echo "Same PAT against catalog.mendix.com should 200 (or at least not 401)."
98+
echo
99+
100+
probe "GET catalog /rest/catalog/v3/entities" \
101+
GET "$CATALOG/rest/catalog/v3/entities?limit=1"
102+
probe "GET catalog /v1/register (doc example)" \
103+
GET "$CATALOG/v1/register"
104+
probe "GET catalog /" GET "$CATALOG/"
105+
106+
echo "## Invalid PAT — confirms ErrUnauthenticated shape"
107+
echo
108+
probe "GET /v1/content with bad PAT" \
109+
GET "$MARKETPLACE/v1/content?limit=1" \
110+
-H "Authorization: MxToken obviously-not-a-real-token"
111+
# Note: second -H "Authorization:" overrides the first; that's what we want
112+
# to test, but curl's -H handling sends both. Use --header to replace? Actually
113+
# curl uses the last occurrence, which is what we want here.
114+
115+
echo "## Summary — fill in after running"
116+
echo
117+
echo "- [ ] \`/v1/content\` (list) returns 200 and list-shaped JSON"
118+
echo "- [ ] \`/v1/content/{id}\` (detail) returns 200 and describes one module"
119+
echo "- [ ] \`?search=…\` parameter is accepted"
120+
echo "- [ ] Versions are available: which path? inline in detail?"
121+
echo "- [ ] Download URL for .mpk: which path?"
122+
echo "- [ ] Bad PAT returns: 401 / 403 / other?"
123+
echo
124+
echo "**Next step**: feed findings into \`docs/11-proposals/PROPOSAL_marketplace_modules.md\`"
125+
echo "to correct the endpoint list and base URL."
126+
} > "$REPORT"
127+
128+
echo "report written to $REPORT"
129+
echo " (PAT redacted — safe to paste findings into proposals)"

0 commit comments

Comments
 (0)