CI is red on `main` and on every open PR (including the Dependabot PRs
#1531, #1552–#1554) with:
```
panic: file requires newer Go version go1.27 (application built with go1.26)
golangci-lint exit with code 2
```
## Cause
`actions/setup-go` with `go-version: 'stable'` started resolving to
**go1.27.0**. The pinned golangci-lint **v2.11.4** release binary is
built with **go1.26**, and its `go/types` refuses to typecheck source
files declaring a newer language version. Nothing in the failing PRs is
at fault.
## Fix
Bump to **golangci-lint v2.13.1**, whose release binaries are built with
go1.27, so linting works under `stable` again.
That bump also pulls in newer linter versions, which surface 57 findings
this tree did not have before. Handled as follows:
| Linter | Count | Resolution |
|---|---|---|
| `goconst` | 50 | 39 were repeated literals in `_test.go` files —
goconst started counting those in v2.12.0 (golangci-lint#6480 exposed
`ignore-tests`). Fixture data like `"1.0.0"` (89 occurrences) is not a
missing constant, so `goconst.ignore-tests: true`. The other 11 were
real duplication in production code (OpenAPI tags, the `bearer` security
scheme name, `$ref`, `http`/`https`) and became named constants. |
| `gosec` G710 | 1 | **True positive, fixed.** See below. |
| `staticcheck` SA1019 | 6 | Go 1.26 deprecated `ecdsa.PublicKey.X/Y`
and `PrivateKey.D`. Annotated with the same targeted `nolint` +
rationale already used for `ScalarBaseMult` in
`cmd/publisher/auth/common.go`. |
### The open redirect is real
`TrailingSlashMiddleware` copied the entire `*url.URL` before rewriting
the path. For an absolute-form request URI — legal for a Go HTTP server
to parse, e.g. `GET http://evil.com/foo/ HTTP/1.1` — `r.URL.Scheme` and
`r.URL.Host` are populated, and they were echoed straight back in the
`Location` header. The redirect target is now built from the cleaned
path and query alone. The existing `path.Clean` hardening for
GHSA-v8vw-gw5j-w7m6 (protocol-relative `//evil.com/`) is unchanged.
### Also
Switched `gomodguard` → `gomodguard_v2`; the former is deprecated as of
v2.12.0 and was emitting a warning on every run.
## Verification
- `golangci-lint v2.13.1` against this tree: **0 issues**, no
deprecation warnings
- `make validate`: all validations passed
- `go build ./...` and tests for every touched package pass (DB-backed
tests need Postgres; left to CI)
## Note on migrating the ecdsa key paths
Moving those six sites to `PublicKey.Bytes` /
`ParseUncompressedPublicKey` / `crypto/ecdh` touches key parsing and
signature verification. It should be its own reviewed PR rather than
riding along on a CI unblock. Happy to open one.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.38.0 to
0.40.0.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="d3398d06de"><code>d3398d0</code></a>
go.mod: update golang.org/x dependencies</li>
<li><a
href="57549bfb0d"><code>57549bf</code></a>
sumdb: ignore unrelated hashes in Lookup</li>
<li><a
href="96f62ae6e9"><code>96f62ae</code></a>
sumdb/tlog: fix TileHashReader authentication bypass</li>
<li><a
href="13be9020bb"><code>13be902</code></a>
go.mod: update golang.org/x dependencies</li>
<li>See full diff in <a
href="https://github.com/golang/mod/compare/v0.38.0...v0.40.0">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps
[github.com/pulumi/pulumi/sdk/v3](https://github.com/pulumi/pulumi) from
3.255.0 to 3.257.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pulumi/pulumi/releases">github.com/pulumi/pulumi/sdk/v3's
releases</a>.</em></p>
<blockquote>
<h2>v3.257.0</h2>
<h2>3.257.0 (2026-08-13)</h2>
<h3>Features</h3>
<ul>
<li>[cli] Offer to create a first project after logging in to an account
with no stacks <a
href="https://redirect.github.com/pulumi/pulumi/pull/24133">#24133</a></li>
<li>[cli/do] Auto-assign identifiers to existing stack resources in
<code>pulumi do</code> input expressions, and add <code>pulumi do
show-resources</code> to list them <a
href="https://redirect.github.com/pulumi/pulumi/pull/24184">#24184</a></li>
<li>[cli/do] Make "<code>pulumi do <pkg> <resource>
patch <name></code> work in stateful mode, overlaying the supplied
inputs onto the existing snippet" <a
href="https://redirect.github.com/pulumi/pulumi/pull/24295">#24295</a></li>
<li>[cli/state] Implement <code>pulumi state get</code> to show
individual resources <a
href="https://redirect.github.com/pulumi/pulumi/pull/24191">#24191</a></li>
<li>[cli/do] Fall back to an auto-created project and stack under
PULUMI_HOME when <code>pulumi do</code> is invoked outside of a Pulumi
project <a
href="https://redirect.github.com/pulumi/pulumi/pull/24231">#24231</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[sdkgen/go] Generated output-form invokes pass their arguments to
the core SDK without resolving them first, so invoke dependencies can be
inferred from arguments; generated SDKs now require pulumi SDK v3.255.0
or later <a
href="https://redirect.github.com/pulumi/pulumi/pull/24060">#24060</a></li>
<li>[cli] Make '<code>pulumi stack history events --summary</code>
report the program errors from the language host <a
href="https://redirect.github.com/pulumi/pulumi/pull/24111">#24111</a></li>
<li>[cli/cloud] <code>pulumi api</code>: repeated
<code>-H</code>/<code>--header</code> values for the same header name
now all reach the wire, instead of each one silently overwriting the
last <a
href="https://redirect.github.com/pulumi/pulumi/pull/24180">#24180</a></li>
<li>[cli/package] Maintain <code>--server</code> when adding to the
packages section of Pulumi.yaml <a
href="https://redirect.github.com/pulumi/pulumi/pull/24189">#24189</a></li>
<li>[sdk/go] Fix panics in hooks to not crash the entire process <a
href="https://redirect.github.com/pulumi/pulumi/pull/24218">#24218</a></li>
<li>[programgen/go] <code>for</code> expressions are now generated as Go
loops <a
href="https://redirect.github.com/pulumi/pulumi/pull/24228">#24228</a></li>
<li>[programgen/go] Fix invalid <code>_ := index</code> statement
emitted for resources with a numeric <code>range</code> whose value
variable is unused <a
href="https://redirect.github.com/pulumi/pulumi/pull/24227">#24227</a></li>
<li>[sdk/python] Report an error instead of hanging when a Python
resource depends on its own parent <a
href="https://redirect.github.com/pulumi/pulumi/pull/24230">#24230</a></li>
<li>[sdkgen/go] Generate the missing Go input types for resource input
properties that are deeply nested collections of object types <a
href="https://redirect.github.com/pulumi/pulumi/pull/24236">#24236</a></li>
<li>[programgen/go] Rename properties that collide with reserved names
(e.g. <code>elementType</code>) the same way SDK codegen does, instead
of emitting uncompilable code <a
href="https://redirect.github.com/pulumi/pulumi/pull/24235">#24235</a></li>
<li>[cli/display] Show the value being added when a refresh or provider
diff reports an added property <a
href="https://redirect.github.com/pulumi/pulumi/pull/24245">#24245</a></li>
<li>[cli/plugin] Track when a plugin was last run so <code>pulumi plugin
ls</code> reports an accurate last-used time on all platforms <a
href="https://redirect.github.com/pulumi/pulumi/pull/24251">#24251</a></li>
<li>[engine] Show secrets in diff display when
<code>--show-secrets</code> is passed <a
href="https://redirect.github.com/pulumi/pulumi/pull/24253">#24253</a></li>
<li>[cli] Exit promptly when a command is cancelled while an HTTP
request is being retried <a
href="https://redirect.github.com/pulumi/pulumi/pull/24276">#24276</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[sdk/nodejs] Improve error message when resource registrations are
still pending when pulumi exits <a
href="https://redirect.github.com/pulumi/pulumi/pull/24082">#24082</a></li>
<li>[cli] Pass the invoked command (e.g. <code>pulumi new</code>) to the
browser-based login/signup flow so Pulumi Cloud can attribute signups to
the command that triggered them <a
href="https://redirect.github.com/pulumi/pulumi/pull/24192">#24192</a></li>
</ul>
<h3>Miscellaneous</h3>
<ul>
<li>[sdkgen] Extension-parameterized packages now namespace their
resource and function tokens under their own package name rather than
the base provider's <a
href="https://redirect.github.com/pulumi/pulumi/pull/24143">#24143</a></li>
<li>[java] Upgrade java to v1.35.0 <a
href="https://redirect.github.com/pulumi/pulumi/pull/24202">#24202</a></li>
<li>[backend/diy] The deprecation warning is now an error.
PULUMI_DIY_BACKEND_IGNORE_DEPRECATION_WARNING is now
PULUMI_DIY_BACKEND_IGNORE_DEPRECATION_ERROR. <a
href="https://redirect.github.com/pulumi/pulumi/pull/24216">#24216</a></li>
<li>[java] Upgrade java to v1.36.0 <a
href="https://redirect.github.com/pulumi/pulumi/pull/24243">#24243</a></li>
<li>[sdk/dotnet] Upgrade dotnet to v3.111.1 <a
href="https://redirect.github.com/pulumi/pulumi/pull/24249">#24249</a></li>
</ul>
<h2>v3.256.0</h2>
<h2>3.256.0 (2026-08-04)</h2>
<h3>Features</h3>
<ul>
<li>[cli] Add <code>--ignore-protect</code> flag to <code>pulumi
up</code>, <code>pulumi preview</code> and <code>pulumi destroy</code>
to allow deleting protected resources without unprotecting them in the
state first <a
href="https://redirect.github.com/pulumi/pulumi/pull/24053">#24053</a></li>
<li>[cli/env] Add an optional <code>--export-env-vars</code> flag to the
<code>env provider {aws,azure,gcp}-login</code> commands to also set the
standard SDK environment variables referencing the login outputs <a
href="https://redirect.github.com/pulumi/pulumi/pull/24055">#24055</a></li>
<li>[cli] Add a <code>--server</code> flag to <code>pulumi package
add</code>, <code>publish</code>, <code>get-schema</code>,
<code>get-mapping</code>, <code>gen-sdk</code>, <code>info</code> and
<code>pulumi schema check</code> that skips package resolution and uses
the given URL as the plugin download URL <a
href="https://redirect.github.com/pulumi/pulumi/pull/24107">#24107</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pulumi/pulumi/blob/master/CHANGELOG.md">github.com/pulumi/pulumi/sdk/v3's
changelog</a>.</em></p>
<blockquote>
<h2>3.257.0 (2026-08-13)</h2>
<h3>Features</h3>
<ul>
<li>[cli] Offer to create a first project after logging in to an account
with no stacks <a
href="https://redirect.github.com/pulumi/pulumi/pull/24133">#24133</a></li>
<li>[cli/do] Auto-assign identifiers to existing stack resources in
<code>pulumi do</code> input expressions, and add <code>pulumi do
show-resources</code> to list them <a
href="https://redirect.github.com/pulumi/pulumi/pull/24184">#24184</a></li>
<li>[cli/do] Make "<code>pulumi do <pkg> <resource>
patch <name></code> work in stateful mode, overlaying the supplied
inputs onto the existing snippet" <a
href="https://redirect.github.com/pulumi/pulumi/pull/24295">#24295</a></li>
<li>[cli/state] Implement <code>pulumi state get</code> to show
individual resources <a
href="https://redirect.github.com/pulumi/pulumi/pull/24191">#24191</a></li>
<li>[cli/do] Fall back to an auto-created project and stack under
PULUMI_HOME when <code>pulumi do</code> is invoked outside of a Pulumi
project <a
href="https://redirect.github.com/pulumi/pulumi/pull/24231">#24231</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[sdkgen/go] Generated output-form invokes pass their arguments to
the core SDK without resolving them first, so invoke dependencies can be
inferred from arguments; generated SDKs now require pulumi SDK v3.255.0
or later <a
href="https://redirect.github.com/pulumi/pulumi/pull/24060">#24060</a></li>
<li>[cli] Make '<code>pulumi stack history events --summary</code>
report the program errors from the language host <a
href="https://redirect.github.com/pulumi/pulumi/pull/24111">#24111</a></li>
<li>[cli/cloud] <code>pulumi api</code>: repeated
<code>-H</code>/<code>--header</code> values for the same header name
now all reach the wire, instead of each one silently overwriting the
last <a
href="https://redirect.github.com/pulumi/pulumi/pull/24180">#24180</a></li>
<li>[cli/package] Maintain <code>--server</code> when adding to the
packages section of Pulumi.yaml <a
href="https://redirect.github.com/pulumi/pulumi/pull/24189">#24189</a></li>
<li>[sdk/go] Fix panics in hooks to not crash the entire process <a
href="https://redirect.github.com/pulumi/pulumi/pull/24218">#24218</a></li>
<li>[programgen/go] <code>for</code> expressions are now generated as Go
loops <a
href="https://redirect.github.com/pulumi/pulumi/pull/24228">#24228</a></li>
<li>[programgen/go] Fix invalid <code>_ := index</code> statement
emitted for resources with a numeric <code>range</code> whose value
variable is unused <a
href="https://redirect.github.com/pulumi/pulumi/pull/24227">#24227</a></li>
<li>[sdk/python] Report an error instead of hanging when a Python
resource depends on its own parent <a
href="https://redirect.github.com/pulumi/pulumi/pull/24230">#24230</a></li>
<li>[sdkgen/go] Generate the missing Go input types for resource input
properties that are deeply nested collections of object types <a
href="https://redirect.github.com/pulumi/pulumi/pull/24236">#24236</a></li>
<li>[programgen/go] Rename properties that collide with reserved names
(e.g. <code>elementType</code>) the same way SDK codegen does, instead
of emitting uncompilable code <a
href="https://redirect.github.com/pulumi/pulumi/pull/24235">#24235</a></li>
<li>[cli/display] Show the value being added when a refresh or provider
diff reports an added property <a
href="https://redirect.github.com/pulumi/pulumi/pull/24245">#24245</a></li>
<li>[cli/plugin] Track when a plugin was last run so <code>pulumi plugin
ls</code> reports an accurate last-used time on all platforms <a
href="https://redirect.github.com/pulumi/pulumi/pull/24251">#24251</a></li>
<li>[engine] Show secrets in diff display when
<code>--show-secrets</code> is passed <a
href="https://redirect.github.com/pulumi/pulumi/pull/24253">#24253</a></li>
<li>[cli] Exit promptly when a command is cancelled while an HTTP
request is being retried <a
href="https://redirect.github.com/pulumi/pulumi/pull/24276">#24276</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[sdk/nodejs] Improve error message when resource registrations are
still pending when pulumi exits <a
href="https://redirect.github.com/pulumi/pulumi/pull/24082">#24082</a></li>
<li>[cli] Pass the invoked command (e.g. <code>pulumi new</code>) to the
browser-based login/signup flow so Pulumi Cloud can attribute signups to
the command that triggered them <a
href="https://redirect.github.com/pulumi/pulumi/pull/24192">#24192</a></li>
</ul>
<h3>Miscellaneous</h3>
<ul>
<li>[sdkgen] Extension-parameterized packages now namespace their
resource and function tokens under their own package name rather than
the base provider's <a
href="https://redirect.github.com/pulumi/pulumi/pull/24143">#24143</a></li>
<li>[java] Upgrade java to v1.35.0 <a
href="https://redirect.github.com/pulumi/pulumi/pull/24202">#24202</a></li>
<li>[backend/diy] The deprecation warning is now an error.
PULUMI_DIY_BACKEND_IGNORE_DEPRECATION_WARNING is now
PULUMI_DIY_BACKEND_IGNORE_DEPRECATION_ERROR. <a
href="https://redirect.github.com/pulumi/pulumi/pull/24216">#24216</a></li>
<li>[java] Upgrade java to v1.36.0 <a
href="https://redirect.github.com/pulumi/pulumi/pull/24243">#24243</a></li>
<li>[sdk/dotnet] Upgrade dotnet to v3.111.1 <a
href="https://redirect.github.com/pulumi/pulumi/pull/24249">#24249</a></li>
</ul>
<h2>3.256.0 (2026-08-04)</h2>
<h3>Features</h3>
<ul>
<li>[cli] Add <code>--ignore-protect</code> flag to <code>pulumi
up</code>, <code>pulumi preview</code> and <code>pulumi destroy</code>
to allow deleting protected resources without unprotecting them in the
state first <a
href="https://redirect.github.com/pulumi/pulumi/pull/24053">#24053</a></li>
<li>[cli/env] Add an optional <code>--export-env-vars</code> flag to the
<code>env provider {aws,azure,gcp}-login</code> commands to also set the
standard SDK environment variables referencing the login outputs <a
href="https://redirect.github.com/pulumi/pulumi/pull/24055">#24055</a></li>
<li>[cli] Add a <code>--server</code> flag to <code>pulumi package
add</code>, <code>publish</code>, <code>get-schema</code>,
<code>get-mapping</code>, <code>gen-sdk</code>, <code>info</code> and
<code>pulumi schema check</code> that skips package resolution and uses
the given URL as the plugin download URL <a
href="https://redirect.github.com/pulumi/pulumi/pull/24107">#24107</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[backend/service] Fix <code>pulumi login --insecure</code> not being
reflected in the stack's service secrets manager state, which caused TLS
verification failures against self-hosted backends using self-signed
certificates <a
href="https://redirect.github.com/pulumi/pulumi/pull/24134">#24134</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="5a7ae5c7b7"><code>5a7ae5c</code></a>
TestNewDefaultOrgResolution: make sure promises are done (<a
href="https://redirect.github.com/pulumi/pulumi/issues/24307">#24307</a>)</li>
<li><a
href="2b0c722908"><code>2b0c722</code></a>
implement the <code>state get</code> command (<a
href="https://redirect.github.com/pulumi/pulumi/issues/24191">#24191</a>)</li>
<li><a
href="c73539f4be"><code>c73539f</code></a>
securestore: add macOS keychain backends (<a
href="https://redirect.github.com/pulumi/pulumi/issues/24211">#24211</a>)</li>
<li><a
href="53a590bdc6"><code>53a590b</code></a>
update yaml to 1.38.2 (<a
href="https://redirect.github.com/pulumi/pulumi/issues/24297">#24297</a>)</li>
<li><a
href="eaf1315db0"><code>eaf1315</code></a>
Honor the request context while an HTTP retry backs off (<a
href="https://redirect.github.com/pulumi/pulumi/issues/24276">#24276</a>)</li>
<li><a
href="c95645f92e"><code>c95645f</code></a>
Generate Go input types for deeply nested collections of objects (<a
href="https://redirect.github.com/pulumi/pulumi/issues/24236">#24236</a>)</li>
<li><a
href="ca7856ce88"><code>ca7856c</code></a>
Add stateful patch method (<a
href="https://redirect.github.com/pulumi/pulumi/issues/24295">#24295</a>)</li>
<li><a
href="67cff339ba"><code>67cff33</code></a>
Update dependency pulumi/pulumi-hcl to v0.15.0 (<a
href="https://redirect.github.com/pulumi/pulumi/issues/24293">#24293</a>)</li>
<li><a
href="ad9f49196b"><code>ad9f491</code></a>
Convert <code>go-nested-collections</code> to a conformance test (<a
href="https://redirect.github.com/pulumi/pulumi/issues/24233">#24233</a>)</li>
<li><a
href="8c419838d7"><code>8c41983</code></a>
Add a conformance test for hooks that panic and fix Go runtime to pass
(<a
href="https://redirect.github.com/pulumi/pulumi/issues/24218">#24218</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/pulumi/pulumi/compare/v3.255.0...v3.257.0">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Deletes `complete.md` and cleans up the last references to the
pre-restructuring docs layout.
## Why `complete.md` goes
It is 2,944 lines (31% of all documentation lines in the repo)
self-described as *"all documentation from the docs/ directory compiled
into a single markdown file"*. But:
- **No generator exists.** No make target, no workflow, no script. `grep
-rn "complete\.md"` finds **zero** references anywhere in the repo.
- **It mirrors a docs tree that no longer exists** — `docs/guides/`,
`docs/explanations/`, `docs/concepts/`.
- **All 72 of its relative links are broken**, and six of the basenames
it references exist nowhere in the repo.
- **~14 current docs are missing from it entirely** (`about.mdx`,
`authentication.mdx`, `package-types.mdx`, both CHANGELOGs, ...).
- **Its `server.json` examples pin the superseded `2025-07-09` schema**
(current is `2025-12-11`).
The strongest argument is its own last commit. [PR
#1278](https://github.com/modelcontextprotocol/registry/pull/1278)
closed [issue
#767](https://github.com/modelcontextprotocol/registry/issues/767) — a
real user-reported CLI flag bug — by editing **only `complete.md`**. A
genuine fix landed in a file nobody reads, while the docs a reader would
actually find stayed wrong.
A generated file with no generator degrades into a trap: authoritative
enough that people edit it, with nothing validating it. If the
LLM-consumption use case is worth keeping, the right shape is a `make
docs-bundle` target plus a `check-docs-bundle` CI job mirroring the
existing `check-schema` pattern — happy to do that instead if you would
rather keep it.
## Remaining stale references
| File | Was | Now |
|---|---|---|
| `contributing/add-package-registry.md` | Add
`docs/guides/publishing/publish-[yourregistry].md`, update
`docs/guides/publishing/README.md` | Add a section to
`package-types.mdx`. These were the **last live references** to the
obsolete `docs/guides/` layout outside `complete.md` |
| `administration/maintainer-onboarding.md` | Add them to "Current key
maintainers" in README | "Registry Working Group" — the section that
actually exists |
| `reference/README.md` | Omitted 6 reference docs | Adds
`api/extensions.md`, `api/openapi.yaml`, `api/CHANGELOG.md`,
`server-json/CHANGELOG.md`, `server-json/CONTRIBUTING.md`,
`server-json/draft/` |
| `docs/README.md` | Index omitted `community-projects.md` | Listed |
| `reference/api/generic-registry-api.md` | `PUT .../versions/{version}`
"not implemented by official registry" | It **is** implemented
([edit.go:36](https://github.com/modelcontextprotocol/registry/blob/main/internal/api/handlers/v0/edit.go#L36)),
and `official-registry-api.md` already lists it as an admin endpoint |
| `reference/api/official-registry-api.md` | Omitted 3 registered routes
| Adds `POST /v0.1/validate` (which `mcp-publisher validate` calls),
`GET /v0.1/ping`, `GET /v0.1/version`, and notes these plus `/health`
are absent from `openapi.yaml` |
| `server-json/official-registry-requirements.md` | Per-registry
verification → `quickstart.mdx` | → `package-types.mdx`, which has an
Ownership Verification section per registry |
| `design/design-principles.md` | Sections 1,2,3,4,**6**,7 | Renumbered
1–6 |
| `contributing/releasing.md` | Steps 1,2,3,**5**,6 | Renumbered 1–5 |
I left the sibling `DELETE` claim in `generic-registry-api.md` alone —
it is accurate, no DELETE route is registered (the `http.MethodDelete`
hit in `server.go` is CORS config, not a route).
## Staleness banners rather than rewrites
**`design/tech-architecture.md`** is substantially fictional. Rather
than a vague "may be outdated", the banner lists what I verified is
wrong:
- Describes Helm-chart deployment; the registry is a plain `Deployment`
([registry.go:65](https://github.com/modelcontextprotocol/registry/blob/main/deploy/pkg/k8s/registry.go#L65)).
Helm is used only for third-party components.
- Diagram shows a `StatefulSet` on port **27017** — MongoDB's port. The
DB is PostgreSQL on 5432 via the CloudNativePG operator.
- Documents a `verify-domain` challenge flow (`POST /verify-domain`,
`/verify-domain/check`, server-issued tokens) that **was never built**.
- Documents `/admin/*` routes that are not registered.
- Says the DB stores user auth state and DNS verification records; only
`servers` and `server_extensions` tables exist.
**`design/roadmap.md`** still says "Phase 1: MVP/Go-Live (Current
Focus)" ~11 months after launch. I added a dated note rather than
inventing a current phase — that is a working-group call.
## Verification
All **101** remaining relative links across every `.md`/`.mdx` in the
repo resolve. The only two non-resolving matches are the intentional
`[project-name](link)` template placeholder and the moderation link
fixed in #1518.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The README prerequisites were both stale, and the docs restated the Go
version in three places.
## Prerequisites: name the source, do not restate the version
| README said | Reality |
|---|---|
| `Go 1.24.x` | `go 1.26` in
[go.mod](https://github.com/modelcontextprotocol/registry/blob/main/go.mod)
|
| `golangci-lint v2.4.0` | `v2.11.4` pinned in
[ci.yml:30](https://github.com/modelcontextprotocol/registry/blob/main/.github/workflows/ci.yml#L30)
|
Rather than swap in fresher numbers — which only resets the clock on the
same drift — this **removes the numbers** and names the authoritative
file:
```
- **Go** - version per the `go` directive in go.mod; the Go toolchain fetches it for you
- **golangci-lint** - version per the `golangci-lint-action` pin in ci.yml, so local lint matches CI
```
The Go version was stated in **three** places, which is exactly why all
three drifted together. All three now point at a single source, so the
prerequisites list cannot go stale.
Two notes on why the numbers earn so little in prose:
- **Go corrects itself.** `go.mod` has no `toolchain` directive, so
under the default `GOTOOLCHAIN=auto` the toolchain downloads the
required version automatically. A contributor on an older Go gets an
upgrade, not a failure — it only hard-errors under `GOTOOLCHAIN=local`.
(An earlier version of this description said such a contributor "cannot
build"; that was too strong.)
- **golangci-lint does not.** Version skew here genuinely changes what
you see: running CI's config under a newer golangci-lint (2.12.2)
surfaces 23 `goconst` findings in
`cmd/publisher/commands/validate_test.go` that CI's pinned 2.11.4 does
not report. That is why the README now points at the pin rather than a
number someone has to keep in sync.
## `make check` does more than documented
Documented in three files as "lint, unit tests and integration tests".
Actually [`check: dev-down lint validate
test-all`](https://github.com/modelcontextprotocol/registry/blob/main/Makefile#L85)
— it also runs schema validation and **stops your running `dev-compose`
environment**. Worth knowing before running it mid-session. The
Makefile's own `##` help string already said this correctly; only the
prose was stale.
## Other verified corrections
- **README project structure** omitted `cmd/registry/` — the server
entry point and ko/goreleaser build target — and `internal/importer/`.
- **`tests/integration/README.md`** said the suite launches **MongoDB**.
It launches PostgreSQL (`postgres-integration-test`), as the same file
admits nine lines later. It also cited `/v0/servers/{server_id}`, a path
removed a while ago; the test actually calls `GET /v0/servers` and `GET
/v0/servers/{serverName}/versions/latest`
([main.go:210,255](https://github.com/modelcontextprotocol/registry/blob/main/tests/integration/main.go#L210)).
- **`scripts/mirror_data/README.md`** pointed at
`internal/database/migrations/008_separate_official_metadata.sql`, which
does not exist — that migration is `009_`, while `008_` is
`clean_invalid_data.sql`. (Migration 008's own header still calls itself
"007a", which is how the numbering slipped.) Also swapped two "edit line
NN" pointers for identifier names, since both had already drifted
(`maxMigration` is at :30 not :24; the connection string at :23 not
:17), and corrected the fetch URL from `/v0.1/servers` to the
`/v0/servers` the script actually requests.
- **`.env.example`** was missing
`MCP_REGISTRY_ENABLE_REGISTRY_VALIDATION`, even though the config reads
it
([config.go:18](https://github.com/modelcontextprotocol/registry/blob/main/internal/config/config.go#L18))
and README:50 tells contributors to set it while pointing at
`.env.example` as *the* reference.
- **`docker-compose.yml`** set `MCP_REGISTRY_ENVIRONMENT`, which nothing
reads — no `ENVIRONMENT` env tag in `internal/config`, and no other
occurrence in the repo. Removed. (The Pulumi-side
`mcp-registry:environment` key is a separate, real thing and is
untouched.)
- **Deleted `CHANGES.md`** — 0 bytes, untouched since the squashed
history base, zero references anywhere.
## Verification
`docker compose config` validates. `grep` for `Go 1.x` / `golangci-lint
vX` across all `.md`/`.mdx` now returns nothing outside `complete.md`
(which #1522 deletes). Both `../../README.md#pre-requisites` links
resolve and the anchor matches the real `#### Pre-requisites` heading.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Two real defects, plus the CLI reference claims that go with them.
## 1. ECDSA P-384 login instructions cannot work
Every "ECDSA P-384" tab ran the *identical* command to the Ed25519 tab.
Since `--algorithm` defaults to ed25519
([login.go:100](https://github.com/modelcontextprotocol/registry/blob/main/cmd/publisher/commands/login.go#L100)),
a 96-hex key is rejected outright. Verified against a freshly generated
P-384 key:
```
$ mcp-publisher login dns --domain=example.com --private-key=$KEY
Signing in process using key algorithm ed25519
Error: failed to get token: failed to sign timestamp: invalid seed length: expected 32 bytes, got 48
$ mcp-publisher login dns --algorithm ecdsap384 --domain=example.com --private-key=$KEY
Signing in process using key algorithm ecdsap384
Expected proof record: # works
```
`--algorithm` is registered at
[login.go:129](https://github.com/modelcontextprotocol/registry/blob/main/cmd/publisher/commands/login.go#L129)
and described correctly by the CLI's own help, but `grep -rn algorithm
docs/` had **zero** hits for it. Anyone following the ECDSA path in the
docs hit that error with nothing to tell them why.
Fixed at all four in-process ECDSA sites (2 in `authentication.mdx`, 2
in `cli/commands.md`), with a note that cloud signing providers derive
the algorithm from the key itself so the flag does not apply to them.
## 2. `mcp-publisher validate --help` was broken
```
$ mcp-publisher validate --help
Unknown command: validate
...
Use 'mcp-publisher <command> --help' for more information about a command.
```
It printed the very instruction that had just failed. `main.go`
intercepted `--help` for all subcommands and called `printCommandHelp`,
whose switch had no `validate` case — making `ValidateCommand`'s own
help block
([validate.go:120-129](https://github.com/modelcontextprotocol/registry/blob/main/cmd/publisher/commands/validate.go#L120))
unreachable.
Rather than paste a third copy of the help text, `printCommandHelp` now
returns whether it handled the command, and the caller falls through to
normal dispatch when it did not. Commands own their own `--help`, and
any future command with this shape works automatically.
| Command | Before | After |
|---|---|---|
| `validate --help` | `Unknown command`, exit 0 | prints its help, exit
0 |
| `publish --help` | works | works |
| `init -h` | works | works |
| `bogus --help` | `Unknown command`, exit 0 | `Unknown command`, **exit
1** |
## 3. CLI reference corrections
- **`--registry` is not global.** It exists only on `login`; other
commands read the URL from the stored token. `publish --registry=URL`
silently treats the flag as the `server.json` path.
`cmd/publisher/README.md` had exactly this broken example.
- **`--token` was undocumented** despite `github-actions.mdx:123`
depending on it. Now documented, noting it is `login github` only.
- **`init` takes no flags** and does not prompt; it writes `TODO:`
placeholders. The reference said `init [options]` and "Prompts for
missing required fields".
- **Refreshed the `--help` transcript** in `quickstart.mdx`, which
listed only 4 of 6 commands. Now byte-for-byte identical to real output
(diffed).
- **Added `validate`** to the command list in `cmd/publisher/README.md`.
## Verification
`go build` and `go test ./cmd/...` pass. All four help paths exercised
with exit codes checked. The 23 `goconst` findings in `validate_test.go`
are pre-existing — identical count on pristine `main`, none in
`main.go`. Quickstart transcript diffed against real output.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The admin takedown script cannot work as written, and the runbook that
documents it has the same problem.
## The bug
`tools/admin/takedown.sh` sent `PUT` with a `?status=deleted` query
parameter to two routes:
| What the script sent | Reality |
|---|---|
| `PUT /v0/servers/{name}/versions/{version}?status=deleted` | Route
exists, but requires a full `ServerJSON` body and has no `status` query
parameter |
| `PUT /v0/servers/{name}?status=deleted` | **Not registered at all** —
the whole-server takedown path 404s |
The real endpoints are `PATCH
/v0/servers/{name}/versions/{version}/status` and `PATCH
/v0/servers/{name}/status`
([status.go:83](https://github.com/modelcontextprotocol/registry/blob/main/internal/api/handlers/v0/status.go#L83),
[:198](https://github.com/modelcontextprotocol/registry/blob/main/internal/api/handlers/v0/status.go#L198)),
both taking `{"status": ..., "statusMessage": ...}`. `edit.go` even says
so in its own description: use the status endpoint for status changes.
## Script changes
- Send `PATCH` with a JSON body built via `jq`
- **Require `VERSION` or `ALL_VERSIONS=true` explicitly.** Previously a
missing `VERSION` meant "entire server". Since `PATCH .../status`
updates *every* version, an operator who simply forgot `VERSION` would
have taken down the whole server. Now that needs saying out loud.
- Support `STATUS` (default `deleted`) and `STATUS_MESSAGE`, so a
takedown can record its reason
- `set -euo pipefail`, non-zero exit on HTTP errors, and print the
response body so huma error detail is visible instead of being swallowed
## Runbook changes
- `GET /v0/servers/{name}` is not a route — use `GET
.../versions/latest` (which is supported, see
[servers.go:155-178](https://github.com/modelcontextprotocol/registry/blob/main/internal/api/handlers/v0/servers.go#L155))
- Replace the per-version `?status=deleted` loop with the single
all-versions `PATCH .../status` call, which reports `updatedCount`
- Keep the per-version `PUT` loop for *content* edits, which genuinely
has no bulk endpoint, and show that it needs the full body
- Correct the closing note claiming server-wide changes must be applied
per version — true for content, not for status
- Fix the broken `moderation-guidelines.md` link (dead since the docs
restructuring; the file is now
`modelcontextprotocol-io/moderation-policy.mdx`)
## Verification
`shellcheck` clean, `bash -n` clean, and all three guard paths exercised
(no args / neither VERSION nor ALL_VERSIONS / both set). Both `PATCH`
paths confirmed present in `docs/reference/api/openapi.yaml`. I did not
run a live takedown against production.
Kept on `/v0` rather than `/v0.1` to match the existing admin/deploy
convention — happy to switch if you would rather admin tooling target
the frozen version.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The cargo registry type has been live since v1.8.0 (#1207).
This PR only updates the schema examples so they match reality.
- Add "cargo" to registryType.examples
- Add "https://crates.io" to registryBaseUrl.examples
No behaviour change.
Note: versioned schemas are synced from modelcontextprotocol/static.
A follow-up there keeps this durable across schema sync.
Co-authored-by: Wolfe-Jam <wolfejam77@gmail.com>
The three deployment links in `docs/contributing/releasing.md` use
`../../../`, which resolves above the repository root and 404s on
GitHub. The file lives in `docs/contributing/`, so the repo root is two
levels up and `../../` is correct.
This fixes the links to `deploy-production.yml`, `deploy-staging.yml`,
and `deploy/README.md` (all three targets exist at the repo root). No
content change.
## Summary
Promote the production registry image from `1.8.0` to
[`1.8.1`](https://github.com/modelcontextprotocol/registry/releases/tag/v1.8.1).
This release includes #1509, which adds a short ingress cache and a
scoped rate-limit increase for the exact public registry-list endpoints.
## Staging verification
- release tag points to `f52dc8525a`, the
commit deployed to staging
- staging deployment and CI workflows completed successfully
- both registry replicas became ready with zero restarts
- rendered NGINX configuration kept the root route at 180 RPM with
buffering off
- exact `/v0/servers` and `/v0.1/servers` routes rendered at 600 RPM
with buffering on
- live cache probe returned `MISS`, then `HIT`
- health and unrelated routes remained uncached
- no application 5xx, serious NGINX errors, or application error logs
were observed after rollout
## Release artifact
- release workflow completed successfully
- `ghcr.io/modelcontextprotocol/registry:1.8.1` is available for
`linux/amd64` and `linux/arm64`
## Deployment and rollback
Merging this PR triggers the production Pulumi deployment automatically.
Monitor registry pod readiness, NGINX reloads, cache behavior, origin
request volume, 429/499/5xx responses, and publish requests exceeding 10
seconds.
Rollback by restoring `mcp-registry:imageTag` to `1.8.0`.
## Summary
- cache successful public list responses for `/v0/servers` and
`/v0.1/servers` at ingress-nginx for 30 seconds
- give only those exact cached paths a 600 RPM per-controller budget
- preserve the existing 180 RPM limit for publish, auth, mutation,
detail, and other routes
- expose `X-Registry-Cache` to make cache MISS/HIT behavior directly
observable
## Why
Production ingress logs show that the current 180 RPM per-controller
limit rejects legitimate bulk pagination before it reaches the
application. The affected traffic is overwhelmingly registry-list reads,
not publishing.
A ten-minute production sample contained 17,836 successful list
responses but only 3,188 unique URLs: 82.1% were repeated requests,
representing roughly 1 GB of duplicate response bodies. Raising the list
limit without caching would increase pressure on the application and its
shared PostgreSQL pool. The short ingress cache absorbs repeated
cursor-page reads before raising their scoped client budget.
Publish latency is a separate concern. Reducing read pressure may help
indirectly, but slow external package validation is intentionally out of
scope for this PR.
Relates to #826.
## Safety
- caching is limited to exact public GET list paths and keyed by host
plus full request URI
- only 200 responses are cached
- cache lifetime is 30 seconds; newly published entries can therefore
take up to 30 seconds to appear on a cached page
- cache locking coalesces simultaneous misses
- stale cached responses may be served while refreshing or during
transient upstream 5xx/timeouts
- each ingress replica uses at most 1 GB of ephemeral on-disk cache
## Validation
- `go test ./...` in `deploy/`
- `go vet ./...` in `deploy/`
- `git diff --check`
- ingress-nginx chart 4.13.0 in a disposable kind cluster
- generated NGINX configuration passed `nginx -t`
- repeated list request verified `X-Registry-Cache: MISS` followed by
`HIT`
- non-list route verified uncached
- exact list locations verified with the higher rate zone while the
catch-all retained 180 RPM
Nothing was applied to production during investigation or validation.
The Key Files list in `cmd/publisher/README.md` includes a bullet for
`build.sh`, but there is no `build.sh` anywhere in the repo. The
publisher is built with `make publisher`, which runs `go build -o
bin/mcp-publisher ./cmd/publisher` (Makefile), so there is no separate
cross-platform build script.
The other three entries in the same list (`main.go`, `commands/`,
`auth/`) all exist. This removes the stale bullet so the list matches
the actual files in the directory.
## Summary
- The GitHub token method grants `io.github.<org>/*` publish rights
**only to org Owners** (active `admin` membership — `github_at.go`).
- The DNS/HTTP token methods grant `reversed(domain)/*` for any proven
domain, with no `github.io` special-casing and an empty
`BlockedNamespaces` list.
- `<org>.github.io` is served by GitHub Pages from the
`<org>/<org>.github.io` repository. **Push access to that one
repository** — routinely held by ordinary org members, a much weaker bar
than Owner — is enough to serve a key at
`/.well-known/mcp-registry-auth`, exchange it for a JWT, and publish
under the org's entire `io.github.<org>/*` namespace.
- Reject `github.io` (and subdomains) at the shared
`ValidateDomainAndTimestamp` seam used by both DNS and HTTP exchange;
`io.github.*` publishers already have the GitHub method.
## Impact if unsolved
Any org member with write access to the org's GitHub Pages repo (or an
attacker compromising such a member) can mint MCP packages under the
org's trusted namespace — supply-chain poisoning of every downstream
user who installs `<org>`'s servers from the registry, bypassing the
deliberate Owner-only gate.
## Test plan
- New `TestValidateDomainAndTimestampRejectsGitHubPages`: rejects
`my-org.github.io` (incl. mixed case and subdomains), still allows
lookalikes (`github.io.evil-example.com`,
`my-org.github.io.example.com`) and ordinary domains.
- Full `internal/api/handlers/v0/auth` package passes.
Made with [Cursor](https://cursor.com)
Signed-off-by: SashaMIT <sash@ela.city>
Co-authored-by: Cursor <cursoragent@cursor.com>
Consolidates the five open dependabot PRs into a single change so they
can be reviewed and merged together. Each bump was reproduced against
current `main` (`go get` + `go mod tidy` for Go modules; the exact SHA
pins applied for the actions group), rather than merging the individual
branches, to avoid stale `go.sum` conflicts.
## Root module (`go.mod`)
| Dependency | From | To | Supersedes |
|---|---|---|---|
| `google.golang.org/grpc` | 1.82.0 | 1.82.1 | #1479 |
| `github.com/prometheus/client_golang` | 1.23.2 | 1.24.1 | #1475 |
| `github.com/danielgtaylor/huma/v2` | 2.38.0 | 2.39.0 | #1474 |
## Deploy module (`deploy/go.mod`)
| Dependency | From | To | Supersedes |
|---|---|---|---|
| `github.com/pulumi/pulumi-kubernetes/sdk/v4` | 4.32.0 | 4.33.0 | #1449
|
## GitHub Actions (#1476)
- `actions/setup-go` SHA bumped across `ci.yml`, `release.yml`,
`deploy-production.yml`, `deploy-staging.yml`
- `actions/download-artifact` v4 → v8.0.1 in
`close-invalid-publish-prs.yml`
`go mod tidy` re-resolved transitive dependencies in both modules
accordingly.
## Verification
- `go build ./...` passes (root + deploy)
- `go vet ./...` passes
- `govulncheck ./...` reports no `golang.org/x/text` finding (the
GO-2026-5970 fix from #1481 is preserved; tidy pulled x/text to v0.40.0)
## Follow-up
Once this merges, the five superseded PRs (#1479, #1475, #1474, #1449,
#1476) can be closed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from
1.81.1 to 1.82.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/grpc/grpc-go/releases">google.golang.org/grpc's
releases</a>.</em></p>
<blockquote>
<h2>Release 1.82.1</h2>
<h1>Security</h1>
<ul>
<li>server: Stop reading from the connection when flooded by HTTP/2
frames. The default value for this limit is 100 frames, excluding DATA
and HEADERS, and may be changed by setting environment variable
<code>GRPC_GO_EXPERIMENTAL_CONTROL_BUFFER_THROTTLE_LIMIT</code>.</li>
<li>xds/rbac: Support <code>Metadata</code> and
<code>RequestedServerName</code> permissions matcher fields. If present
in a DENY rule, previously these would be ignored and fail-open.</li>
<li>xds/rbac: Fix panic when parsing unsupported fields in
<code>NotRule</code>/<code>NotId</code> permissions.</li>
<li>xds/rbac: Support the deprecated <code>source_ip</code> principal
identifier by treating it as equivalent to
<code>direct_remote_ip</code>.</li>
</ul>
<h2>Release 1.82.0</h2>
<h1>Behavior Changes</h1>
<ul>
<li>server: Remove support for
<code>GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING</code>
environment varibale. Strict incoming RPC path validation (which has
been the default since <code>v1.79.3</code>) can no longer be disabled.
(<a
href="https://redirect.github.com/grpc/grpc-go/issues/9112">#9112</a>)</li>
<li>transport: Add environment variable to change the default max header
list size from <code>16MB</code> to <code>8KB</code>. This may be
enabled by setting
<code>GRPC_GO_EXPERIMENTAL_ENABLE_8KB_DEFAULT_HEADER_LIST_SIZE=true</code>.
This will be enabled by default in a subsequent release. (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9019">#9019</a>)</li>
<li>balancer: Load Balancing policy registry is now case-sensitive. Set
<code>GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES=false</code>
(and file an issue) to revert to case-insensitive behavior. (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9017">#9017</a>)</li>
</ul>
<h1>New Features</h1>
<ul>
<li>experimental/stats: Expose a new API,
<code>NewContextWithLabelCallback</code>, to register a callback that is
invoked when telemetry labels are added. (<a
href="https://redirect.github.com/grpc/grpc-go/issues/8877">#8877</a>)
<ul>
<li>Special Thanks: <a
href="https://github.com/seth-epps"><code>@seth-epps</code></a></li>
</ul>
</li>
<li>client: Return a portion of the response body in the error message,
when the client receives an unexpected non-gRPC HTTP response, to make
debugging easier. (<a
href="https://redirect.github.com/grpc/grpc-go/issues/8929">#8929</a>)
<ul>
<li>Special Thanks: <a
href="https://github.com/chengxilo"><code>@chengxilo</code></a></li>
</ul>
</li>
<li>server: Add environment variable
<code>GRPC_GO_SERVER_GOROUTINE_LABELS</code> that controls setting
<code>runtime/pprof.Labels</code> on goroutines spawned by the server.
Set <code>GRPC_GO_SERVER_GOROUTINE_LABELS=grpc.method=true</code> to add
the <code>grpc.method</code> label on goroutines spawned to handle
incoming requests. (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9082">#9082</a>)
<ul>
<li>Special Thanks: <a
href="https://github.com/dfinkel"><code>@dfinkel</code></a></li>
</ul>
</li>
</ul>
<h1>Bug Fixes</h1>
<ul>
<li>xds/server: Fix a memory leak of HTTP filter instances occurring
when route configurations are updated in-place during a Route Discovery
Service (RDS) update. (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9138">#9138</a>)</li>
<li>grpc: In the deprecated <code>gzip</code> Compressor (used via the
deprecated <code>WithCompressor</code> dial option), enforce the
<code>MaxRecvMsgSize</code> limit on the decompressed message buffer,
preventing excessive memory allocation from highly compressed payloads.
(<a
href="https://redirect.github.com/grpc/grpc-go/issues/9114">#9114</a>)
<ul>
<li>Special Thanks: <a
href="https://github.com/evilgensec"><code>@evilgensec</code></a></li>
</ul>
</li>
<li>stats/opentelemetry: Record retry attempts,
<code>grpc.previous-rpc-attempts</code>, at the call level and not the
attempt level. (<a
href="https://redirect.github.com/grpc/grpc-go/issues/8923">#8923</a>)</li>
<li>encoding: Ensure <code>Close()</code> is always called on readers
returned from <code>Compressor.Decompress</code> if possible. (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9135">#9135</a>)</li>
<li>channelz: Fix the <code>LastMessageSentTimestamp</code> and
<code>LastMessageReceivedTimestamp</code> fields in
<code>SocketMetrics</code> to ensure they contain correct timestamp
values. (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9109">#9109</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ebd8f06a09"><code>ebd8f06</code></a>
Change version to 1.82.1 (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9238">#9238</a>)</li>
<li><a
href="4ea465d4ab"><code>4ea465d</code></a>
Cherry-pick commits (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9236">#9236</a>)</li>
<li><a
href="9494a2cf32"><code>9494a2c</code></a>
Change version to 1.82.1-dev (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9171">#9171</a>)</li>
<li><a
href="bd239854f0"><code>bd23985</code></a>
Change version to 1.82.0 (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9170">#9170</a>)</li>
<li><a
href="0f3086db7a"><code>0f3086d</code></a>
Fix minor issues not covered by PR <a
href="https://redirect.github.com/grpc/grpc-go/issues/9137">#9137</a>
(<a
href="https://redirect.github.com/grpc/grpc-go/issues/9147">#9147</a>)</li>
<li><a
href="fef07fbb2b"><code>fef07fb</code></a>
internal: Split v3procservicepb import into pb and grpc for extproc (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9163">#9163</a>)</li>
<li><a
href="91dd64f4b8"><code>91dd64f</code></a>
transport: surface subsequent data when receiving non-gRPC header (<a
href="https://redirect.github.com/grpc/grpc-go/issues/8929">#8929</a>)</li>
<li><a
href="adc97de952"><code>adc97de</code></a>
test/kokoro: add config for regional-td test (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9158">#9158</a>)</li>
<li><a
href="57c9ff14e0"><code>57c9ff1</code></a>
xds: ensure full-string matching for RBAC Filter rules (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9148">#9148</a>)</li>
<li><a
href="b58f32d9ff"><code>b58f32d</code></a>
server: Set a pprof label on new stream goroutines (<a
href="https://redirect.github.com/grpc/grpc-go/issues/9082">#9082</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/grpc/grpc-go/compare/v1.81.1...v1.82.1">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/modelcontextprotocol/registry/network/alerts).
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Problem
The **Build, Lint, and Validate** CI job is failing on every open PR
(#1480, #1474, #1449) and on `main`. The failing step is `govulncheck`:
```
Vulnerability #1: GO-2026-5970
Infinite loop on invalid input in golang.org/x/text
Found in: golang.org/x/text@v0.38.0
Fixed in: golang.org/x/text@v0.39.0
```
This is **not** caused by any of those PRs' changes —
`govulncheck-action` fetches the live vulnerability database at runtime,
so when GO-2026-5970 was published, every branch based on the current
`main` started failing. The vulnerable symbol is reachable via:
- `auth.DefaultHTTPKeyFetcher.FetchKey` → `http.Client.Do`
- `database.NewTestDB` → `pgx.Connect`
so the scan exits with code 3.
## Fix
Bump the (indirect) `golang.org/x/text` dependency from `v0.38.0` to the
fixed `v0.39.0` and `go mod tidy`.
## Verification
- `govulncheck ./...` no longer reports GO-2026-5970 (confirmed
locally).
- `go build ./...` passes.
## Note
The `deploy/` module pins `golang.org/x/text@v0.37.0`, which is also <
v0.39.0. It is a separate module and is **not** scanned by this CI job
(govulncheck runs `./...` in the root module only), so it does not block
CI. Worth a follow-up bump for hygiene, but out of scope here.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Bumps
[github.com/pulumi/pulumi/sdk/v3](https://github.com/pulumi/pulumi) from
3.251.0 to 3.253.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pulumi/pulumi/releases">github.com/pulumi/pulumi/sdk/v3's
releases</a>.</em></p>
<blockquote>
<h2>v3.253.0</h2>
<h2>3.253.0 (2026-07-14)</h2>
<h3>Features</h3>
<ul>
<li>[auto/go] Support --import-pending-creates for refresh command in Go
Automation API for preview refresh and refresh operations <a
href="https://redirect.github.com/pulumi/pulumi/pull/23833">#23833</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[sdk] Precompose filenames to NFC on macOS when matching ignore
patterns during archive creation, mirroring git's core.precomposeunicode
so composed patterns match decomposed filenames <a
href="https://redirect.github.com/pulumi/pulumi/pull/23566">#23566</a></li>
<li>[cli] Respect the -v log level again so that without -v only
warnings and errors are written to stderr <a
href="https://redirect.github.com/pulumi/pulumi/pull/23910">#23910</a></li>
<li>[codegen] Correctly generate provider resources declared inside PCL
components for Node.js, Python and Go <a
href="https://redirect.github.com/pulumi/pulumi/pull/23904">#23904</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli] Add a <code>--version</code> flag to the <code>pulumi</code>
command that prints the version, same as <code>pulumi version</code> <a
href="https://redirect.github.com/pulumi/pulumi/pull/23898">#23898</a></li>
<li>[cli] Align <code>env</code> commands with the CLI naming
guidelines, making <code>list</code>, <code>remove</code> and
<code>move</code> the canonical names with <code>ls</code>,
<code>rm</code>, <code>delete</code> and <code>mv</code> kept as aliases
<a
href="https://redirect.github.com/pulumi/pulumi/pull/23901">#23901</a></li>
</ul>
<h2>v3.252.0</h2>
<h2>3.252.0 (2026-07-13)</h2>
<h3>Features</h3>
<ul>
<li>[auto] Add <code>import</code> to the generated automation APIs for
NodeJS, Python and Go <a
href="https://redirect.github.com/pulumi/pulumi/pull/23876">#23876</a></li>
<li>[cli] Improve the error message when using Pulumi ESC with a DIY
backend to suggest logging into Pulumi Cloud <a
href="https://redirect.github.com/pulumi/pulumi/pull/23811">#23811</a></li>
<li>[cli] Show command name for cli commands when running any command
that lists logs <a
href="https://redirect.github.com/pulumi/pulumi/pull/23889">#23889</a></li>
<li>[cli/display] Render strings containing non-UTF8 bytes as
b"<!-- raw HTML omitted -->" in diffs and JSON output <a
href="https://redirect.github.com/pulumi/pulumi/pull/23870">#23870</a></li>
<li>[cli/env] Add a <code>--reason</code> flag to <code>pulumi env
open-request</code> to explain the request to approvers <a
href="https://redirect.github.com/pulumi/pulumi/pull/23802">#23802</a></li>
<li>[cli/state] Improve the error message when a resource URN is not
found in the state for <code>pulumi state</code> commands, suggesting
close-matching URNs and how to list the URNs in the stack <a
href="https://redirect.github.com/pulumi/pulumi/pull/23812">#23812</a></li>
<li>[pcl] Allow binding hooks to a resource's <code>onError</code>
option <a
href="https://redirect.github.com/pulumi/pulumi/pull/23838">#23838</a></li>
<li>[sdk/nodejs] Add a <code>production</code> runtime option for
Node.js projects. When set to <code>true</code> in
<code>Pulumi.yaml</code>, <code>pulumi install</code> skips
<code>devDependencies</code> (npm <code>--production</code>, pnpm
<code>--production</code>, yarn <code>--production</code>). <a
href="https://redirect.github.com/pulumi/pulumi/pull/23849">#23849</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[cli] Exit with a non-zero code when a command group such as
<code>pulumi env</code> is given an unknown subcommand or no subcommand
at all <a
href="https://redirect.github.com/pulumi/pulumi/pull/23814">#23814</a></li>
<li>[cli] Fix a panic when displaying a stack-level policy violation <a
href="https://redirect.github.com/pulumi/pulumi/pull/23692">#23692</a></li>
<li>[cli] Make reading non-secret stack outputs and running <code>pulumi
about</code> no longer require the passphrase for passphrase-encrypted
stacks <a
href="https://redirect.github.com/pulumi/pulumi/pull/23820">#23820</a></li>
<li>[cli] Avoid <code>pulumi logs <command></code> showing the log
for the currently running command <a
href="https://redirect.github.com/pulumi/pulumi/pull/23887">#23887</a></li>
<li>[cli/do] Fix calling delete on PF resources that need read called
first <a
href="https://redirect.github.com/pulumi/pulumi/pull/23837">#23837</a></li>
<li>[cli/env] Submit the change request created by <code>pulumi env
open-request</code> so it is pending approval instead of being left as
an unsubmitted draft <a
href="https://redirect.github.com/pulumi/pulumi/pull/23802">#23802</a></li>
<li>[cli/neo] Fix the initial prompt sometimes rendering above the
welcome banner in <code>pulumi neo</code> <a
href="https://redirect.github.com/pulumi/pulumi/pull/23831">#23831</a></li>
<li>[engine] Fix importing a resource whose import identifier differs
from its canonical ID causes the resource to be deleted on a subsequent
update <a
href="https://redirect.github.com/pulumi/pulumi/pull/23834">#23834</a></li>
<li>[programgen] Deduplicate identical apply arguments to avoid
unnecessary Promise.all/pulumi.all/Output.All in generated code <a
href="https://redirect.github.com/pulumi/pulumi/pull/22293">#22293</a></li>
<li>[sdk] Failed resource registrations will return faulted outputs, not
unknown outputs <a
href="https://redirect.github.com/pulumi/pulumi/pull/23844">#23844</a></li>
<li>[sdk/nodejs] Fix empty node_modules folders in serialized function
archives when using pnpm or symlinked workspace packages <a
href="https://redirect.github.com/pulumi/pulumi/pull/23866">#23866</a></li>
</ul>
<h3>Miscellaneous</h3>
<ul>
<li>[sdk/nodejs] Report the TypeScript version in <code>pulumi
about</code> <a
href="https://redirect.github.com/pulumi/pulumi/pull/23850">#23850</a></li>
<li>[sdk/nodejs] Update OpenTelemetry dependencies <a
href="https://redirect.github.com/pulumi/pulumi/pull/23855">#23855</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pulumi/pulumi/blob/master/CHANGELOG.md">github.com/pulumi/pulumi/sdk/v3's
changelog</a>.</em></p>
<blockquote>
<h2>3.253.0 (2026-07-14)</h2>
<h3>Features</h3>
<ul>
<li>[auto/go] Support --import-pending-creates for refresh command in Go
Automation API for preview refresh and refresh operations <a
href="https://redirect.github.com/pulumi/pulumi/pull/23833">#23833</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[sdk] Precompose filenames to NFC on macOS when matching ignore
patterns during archive creation, mirroring git's core.precomposeunicode
so composed patterns match decomposed filenames <a
href="https://redirect.github.com/pulumi/pulumi/pull/23566">#23566</a></li>
<li>[cli] Respect the -v log level again so that without -v only
warnings and errors are written to stderr <a
href="https://redirect.github.com/pulumi/pulumi/pull/23910">#23910</a></li>
<li>[codegen] Correctly generate provider resources declared inside PCL
components for Node.js, Python and Go <a
href="https://redirect.github.com/pulumi/pulumi/pull/23904">#23904</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli] Add a <code>--version</code> flag to the <code>pulumi</code>
command that prints the version, same as <code>pulumi version</code> <a
href="https://redirect.github.com/pulumi/pulumi/pull/23898">#23898</a></li>
<li>[cli] Align <code>env</code> commands with the CLI naming
guidelines, making <code>list</code>, <code>remove</code> and
<code>move</code> the canonical names with <code>ls</code>,
<code>rm</code>, <code>delete</code> and <code>mv</code> kept as aliases
<a
href="https://redirect.github.com/pulumi/pulumi/pull/23901">#23901</a></li>
</ul>
<h2>3.252.0 (2026-07-13)</h2>
<h3>Features</h3>
<ul>
<li>[auto] Add <code>import</code> to the generated automation APIs for
NodeJS, Python and Go <a
href="https://redirect.github.com/pulumi/pulumi/pull/23876">#23876</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[cli] Exit with a non-zero code when a command group such as
<code>pulumi env</code> is given an unknown subcommand or no subcommand
at all <a
href="https://redirect.github.com/pulumi/pulumi/pull/23814">#23814</a></li>
<li>[cli] Fix a panic when displaying a stack-level policy violation <a
href="https://redirect.github.com/pulumi/pulumi/pull/23692">#23692</a></li>
<li>[cli] Make reading non-secret stack outputs and running <code>pulumi
about</code> no longer require the passphrase for passphrase-encrypted
stacks <a
href="https://redirect.github.com/pulumi/pulumi/pull/23820">#23820</a></li>
<li>[cli] Avoid <code>pulumi logs <command></code> showing the log
for the currently running command <a
href="https://redirect.github.com/pulumi/pulumi/pull/23887">#23887</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli] Improve the error message when using Pulumi ESC with a DIY
backend to suggest logging into Pulumi Cloud <a
href="https://redirect.github.com/pulumi/pulumi/pull/23811">#23811</a></li>
<li>[cli] Show command name for cli commands when running any command
that lists logs <a
href="https://redirect.github.com/pulumi/pulumi/pull/23889">#23889</a></li>
<li>[cli/display] Render strings containing non-UTF8 bytes as
b"<!-- raw HTML omitted -->" in diffs and JSON output <a
href="https://redirect.github.com/pulumi/pulumi/pull/23870">#23870</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[cli/do] Fix calling delete on PF resources that need read called
first <a
href="https://redirect.github.com/pulumi/pulumi/pull/23837">#23837</a></li>
<li>[cli/env] Submit the change request created by <code>pulumi env
open-request</code> so it is pending approval instead of being left as
an unsubmitted draft <a
href="https://redirect.github.com/pulumi/pulumi/pull/23802">#23802</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli/env] Add a <code>--reason</code> flag to <code>pulumi env
open-request</code> to explain the request to approvers <a
href="https://redirect.github.com/pulumi/pulumi/pull/23802">#23802</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[cli/neo] Fix the initial prompt sometimes rendering above the
welcome banner in <code>pulumi neo</code> <a
href="https://redirect.github.com/pulumi/pulumi/pull/23831">#23831</a></li>
</ul>
<h3>Improvements</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="94536e530d"><code>94536e5</code></a>
Update first-party Pulumi dependencies (major) (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23913">#23913</a>)</li>
<li><a
href="435c4f36ae"><code>435c4f3</code></a>
Align env commands with the CLI command guidelines (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23901">#23901</a>)</li>
<li><a
href="da11b64f0d"><code>da11b64</code></a>
Add a --version flag to the pulumi command (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23898">#23898</a>)</li>
<li><a
href="03bf3a8cbf"><code>03bf3a8</code></a>
Rename rawStringBytesDisplay to byteStringDisplay (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23909">#23909</a>)</li>
<li><a
href="3344335970"><code>3344335</code></a>
Bump HCL to 0.10.0 (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23890">#23890</a>)</li>
<li><a
href="deb8acfde3"><code>deb8acf</code></a>
Support import pending creates parameter (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23833">#23833</a>)</li>
<li><a
href="54158aeba8"><code>54158ae</code></a>
Precompose filenames to NFC on macOS when matching archive ignore
patterns (#...</li>
<li><a
href="93f6e51d9b"><code>93f6e51</code></a>
logging: fix -v=<n> output (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23910">#23910</a>)</li>
<li><a
href="d8e98e7ccd"><code>d8e98e7</code></a>
Update first-party Pulumi dependencies (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23912">#23912</a>)</li>
<li><a
href="f669f791c5"><code>f669f79</code></a>
Add conformance test for using a provider in a component (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23904">#23904</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/pulumi/pulumi/compare/v3.251.0...v3.253.0">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Promotes production to the
[`v1.8.0`](https://github.com/modelcontextprotocol/registry/releases/tag/v1.8.0)
release.
- `deploy/Pulumi.gcpProd.yaml` → `imageTag: 1.8.0` (one line).
- The release build for `v1.8.0` completed successfully, so the image is
present in ghcr.
- **Merging this triggers `deploy-production.yml`** (it's path-filtered
to `deploy/Pulumi.gcpProd.yaml`); the PR itself doesn't deploy.
### Notable behavior changes in v1.8.0
- **Org-namespace publishing now requires org Owner** (via GitHub login
/ PAT). Member-level publishers lose org publish — intended tightening.
- Stricter validation may reject some previously-accepted package
metadata / names (#1310, #1331, #1411).
- New: cargo (crates.io) package registry support (#1207).
### After merge
- Confirm prod `/v0/version` reports `1.8.0` before treating the rollout
as done.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Fixes#553.
The PyPI and npm validators fetch the version-specific metadata endpoint
(`/pypi/{name}/{version}/json` and the npm equivalent) and report any
non-200 as `<pkg> not found`. That endpoint 404s for two different
reasons though: the package doesn't exist, or it exists and only the
*version* is missing (e.g. a release that hasn't propagated yet). So a
valid package reads as gone:
```diff
- PyPI package 'requests' not found (status: 404)
+ PyPI package 'requests' exists, but version '99.99.99' was not found (status: 404). A newly published release can take a moment to appear on PyPI. Wait and retry, or publish version '99.99.99' before registering it
```
On a version 404 it probes the package-level endpoint
(`/pypi/{name}/json`, `/{name}`) with a `HEAD` to tell the two apart,
and reports 429/5xx as transient rather than "not found". `HEAD` so it
reads a status without pulling the whole packument. The probe carries
its own 3s deadline: it only refines the error message, so a hung probe
must not stretch the validator past the ~10s-per-registry budget the
publish path assumes. Same probe-and-classify shape as the existing
cargo validator.
The fetch is split into `validatePyPIPackage` / `validateNPMPackage`
behind `export_test.go` so the branches are testable with `httptest`,
the same seam cargo uses.
### Testing
- [x] hermetic `httptest` for the status matrix (version-missing,
package-missing, 5xx, 429, inconclusive probe, positive path, scoped
npm); the mocks pin the expected method per endpoint (`GET` fetch,
`HEAD` probe)
- [x] hermetic deadline test: a hung probe is cut off at ~3s and
reported as inconclusive, not "not found"
- [x] existing live package tests still pass, now also hitting the HEAD
probe; on a live 429/5xx they now `t.Skip` as inconclusive instead of
flaking (deliberate: CI runs these against the real registries with no
short-mode gating)
- [x] `gofmt` / `go vet` / `golangci-lint` clean
Out of scope: auto-retry for the propagation race, and SSRF
redirect-pinning parity for the pypi/npm clients (pre-existing, shared
with nuget).
Follow-up to #1436.
`internal/api/cors_test.go` was a placeholder: both `TestCORSHeaders`
and `TestCORSHeaderValues` construct `api.NewServer(...)`, discard it,
and then assert against a locally-built `http.HandlerFunc` that has no
CORS middleware — so they never exercised the real stack.
`TestCORSHeaderValues` only `t.Log`s; `TestCORSHeaders`'s only real
assertion (preflight status in {200,204}) ran against a bare handler
that always returns 200. The comments admit as much ("this is a bit of a
hack", "verified via integration tests").
That empty coverage is exactly why the missing `PATCH` in the CORS
`AllowedMethods` (fixed in #1436) went unnoticed.
#1436 added `TestCORSPreflightAllowedMethods`, which drives the real
wrapped handler through the new `Server.Handler()` accessor and asserts
every routed method — including PATCH — is allowed. With that in place
the placeholder carries no remaining coverage, so this PR removes it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The status endpoints (PATCH /v0/servers/{name}/status and the
per-version one) are served with PATCH, but the CORS middleware's
AllowedMethods lists GET/POST/PUT/DELETE/OPTIONS and never PATCH. So a
cross-origin browser preflight for those endpoints comes back without
the allow headers and the browser blocks the actual request. One-line
fix: add PATCH to the allowed methods.
While here, the existing CORS test turned out to be a placeholder that
never reaches the real wrapped handler (its own comments say so), which
is why this went unnoticed. Added a small Handler() accessor and a
proper preflight test that asserts each routed method including PATCH is
allowed.
## Summary
- add a publisher preflight that rejects non-UTF-8 `server.json` bytes
before parsing
- reject unpaired UTF-16 surrogate escapes inside JSON string fields
before publish/validate requests are sent
- keep valid non-ASCII descriptions, including em dashes, round-tripping
through the publish path
- make the publisher test token helper set `USERPROFILE` as well as
`HOME` so Windows tests use the temp home directory
Closes#1306.
## To verify
- `go test ./cmd/publisher/commands -run
"TestPublishCommand_(Success|PreservesNonASCIIDescription|RejectsInvalidUTF8ServerJSON|RejectsUnpairedSurrogateEscape)$"
-count=1`
- `go test ./cmd/publisher/commands -run TestPublishCommand -count=1`
- `go test ./cmd/publisher/commands -run TestValidateCommand -count=1`
- `git diff --check`
Co-authored-by: Radoslav Dimitrov <radoslav@stacklok.com>
## What
Stage 2 of the auto-close automation (`close-invalid-publish-prs.yml`)
re-derived the PR author association with:
```bash
gh pr view "$PR_NUMBER" --json authorAssociation --jq '.authorAssociation'
```
But `gh pr view --json` has **no** `authorAssociation` field. `gh` exits
non-zero with `Unknown JSON field: "authorAssociation"`, and because the
step runs under `set -euo pipefail`, the whole job aborts **before** it
comments, labels, or closes. Flagged PRs therefore stayed open.
## Why it went unnoticed
- **Stage 1 (detect) was fine** — it reads `author_association` from the
event payload (`github.event.pull_request.author_association`), which is
valid.
- Only the **stage-2 re-derivation** was broken.
- Every prior stage-2 run showed "success" because those PRs weren't
flagged: with no artifact, stage 2 exits early at the artifact check and
never reaches the broken line.
- **[PR
#1438](https://github.com/modelcontextprotocol/registry/pull/1438) was
the first genuine publish-attempt PR** since the automation landed
(#1393), so it was the first to exercise the bug — [run
`29178568034`](https://github.com/modelcontextprotocol/registry/actions/runs/29178568034)
failed on exactly this line.
## Fix
Fetch `author_association` from the REST pulls endpoint, which does
expose it (verified: returns `FIRST_TIME_CONTRIBUTOR` for #1438):
```bash
gh api "repos/$GH_REPO/pulls/$PR_NUMBER" --jq '.author_association'
```
Both `$GH_REPO` and `$PR_NUMBER` are already-sanitized env vars, so no
new injection surface.
## Follow-up
Stage 2 is idempotent (guarded by the `invalid` label), so once merged a
maintainer can re-run it — or simply re-open/re-close — to clean up
#1438.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Adds polygraph (https://polygraph.so) to the **Other** section of
`docs/community-projects.md`, per the *Adding Your Project* instructions
(one-line entry).
polygraph publishes independent behavioral security grades (A–F) for MCP
servers from an open, reproducible harness
(https://github.com/polygraphso/litmus) — it exercises a server's live
tool surface and grades what it does (tool-output injection, undeclared
egress, sensitive-data handling, adversarial-input robustness), then
publishes the results as an adoption-ranked index with per-server
reports. It reads the official registry to discover and version servers,
and adds the independent ratings layer this project's docs note
downstream aggregators can provide.
One-line entry only; no code or schema changes.
Follow-up to #1383, surfaced while validating that change end-to-end
against staging.
## Why
#1383 hardened org-namespace publishing to require Owner (`admin`) role,
read via `GET /user/memberships/orgs`. Validating on staging revealed a
gap: the docs only mention the classic `read:org` scope, but a
**fine-grained PAT** (GitHub's recommended token type) needs a
*different* permission to expose org membership. Without it, GitHub
returns no org memberships for the token, so the exchange silently
grants only the personal namespace — with no hint why org publishing
"doesn't work."
This is **not** a code bug (the behavior is fail-closed and correct
given GitHub's response); it's a documentation/UX gap.
## What
- **Docs** (`authentication.mdx`, `github-actions.mdx`): spell out both
token types —
- Classic PAT → `read:org` scope
- Fine-grained PAT → **Organization permissions → Members → Read-only**
(the equivalent), noting a fine-grained PAT is bound to a single
resource owner.
- Also clarified `read:user` is not required.
- **Test** (`github_at_test.go`): cover the `maxOrgMembershipPages`
pagination cap — when every page is full, the exchange **fails closed**
(no token) rather than returning a possibly-truncated org grant. This
path was previously untested.
- **Comment** (`github_at.go`): qualify the `X-GitHub-SSO` 403 check as
best-effort — we have not confirmed the memberships *list* endpoint
emits that header on SSO enforcement (it may just omit the org). The
check is safe either way, but the comment no longer overstates it as a
guarantee.
## Verification (live, against staging)
Confirmed by exchanging real tokens for `rdimitrov` on
`staging.registry.modelcontextprotocol.io`:
- **Classic `read:org` PAT** across 16 real org memberships → the JWT
granted exactly the 8 **admin** orgs + personal namespace, and **zero**
of the 8 **member** orgs (incl. `stacklok`, `modelcontextprotocol`) —
the core #1383 behavior, working.
- **Fine-grained PAT**: without Members:read → personal namespace only
(fail-closed); after adding Members:read → the org (Owner) namespace is
granted. This is what the new docs describe.
No runtime behavior change here beyond the added test; the docs and
comment are the substance.
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
## The bug (scoped to `github-at`)
When you exchange a GitHub OAuth/PAT token for a registry JWT, the
handler granted `io.github.<org>/*` publish permission for **every**
organization you belong to. It derived that list from [`GET
/users/{username}/orgs`](https://docs.github.com/en/rest/orgs/orgs#list-organizations-for-a-user),
which:
1. returns only **public** org memberships, and
2. carries **no role** — an org Owner and a brand-new member look
identical.
So membership was silently treated as publishing authority. Anyone who
is (or whose public membership lists them as) a member of `acme` could
publish — and, because publish is a pure namespace-glob with no
per-server ownership check, **overwrite** — any server under
`io.github.acme/*`.
## The fix
Switch to [`GET
/user/memberships/orgs`](https://docs.github.com/en/rest/orgs/members#list-organization-memberships-for-the-authenticated-user),
which returns the **authenticated caller's role** per org (and includes
private memberships), and grant the org namespace only when the role is
`admin` (org Owner).
- **Personal namespaces are unchanged** — you always get
`io.github.<your-username>/*`.
- **Org namespaces now require Owner.** GitHub has no org-level
"maintainer" role; org membership is either `admin` (Owner) or `member`.
We grant only on `admin`.
- **`read:org` is the only scope needed.** A minimal token without it
still authenticates and still publishes to your personal namespace; a
genuine missing-scope `403` from the memberships call is treated as "no
admin orgs" rather than a hard failure, so we don't push anyone to
over-scope a token. A `403`/`429` that is actually a rate limit
(`X-RateLimit-Remaining: 0` / `Retry-After`) fails closed instead, so a
throttle can't silently strip a real Owner's org grant. Critically, the
token needs **no repository scopes** — the registry never reads or
writes code, so an org Owner can hand CI a near-powerless `read:org`
token.
The authorization decision stays stateless and delegated to GitHub — no
new storage, no new endpoints, no schema changes — consistent with
[design principle #2](docs/design/design-principles.md) (minimal
operational burden).
### Containing the CI token
The registry-side change makes the org Owner the only one who can mint
org-namespace authority. But if that Owner drops the resulting PAT into
a plain repo secret, **every repository writer** can reach it (via
branch/tag pushes that run repo-controlled build/test code in the
privileged job) — quietly re-widening publish access beyond Owners.
External fork contributors still cannot reach it by default (no secrets
on fork PRs, no branch push), barring misconfigurations like
`pull_request_target`-with-checkout or self-hosted runners on public
repos.
`docs/modelcontextprotocol-io/github-actions.mdx` documents how to
contain that blast radius:
- store the token as a **GitHub Actions Environment secret** (the PAT
example uses `environment:`),
- restrict that environment to the default branch / release tags and
require PR reviews on it, so only reviewed, maintainer-approved code can
reach the token,
- optionally add a **required environment reviewer** for explicit
per-publish approval,
- and avoid the two footguns (`pull_request_target` checkout,
self-hosted runners on public repos).
This shrinks *who holds* the org credential; it does not change the fact
that an authorized publish can still overwrite a different server in the
same namespace until per-server publisher ownership exists (the
follow-up noted below).
## Why this shape, given the alternatives
[Pree's
writeup](https://github.com/modelcontextprotocol/registry/issues/982#issuecomment-3982959559)
([Notion analysis
doc](https://www.notion.so/MCP-Registry-Authorization-Model-Analysis-Issue-982-31736f79f74980bc90c6e53de1c564c5))
is the clearest framing of the problem and the option space, laying out
three broad solutions:
- **Approach A — GitHub App as the authority layer.** Strong model, but
its natural unit of authority is a *repo*, so it needs a repo→server
mapping to authorize a namespace. The safe, flexible version of that
mapping is registry-managed state — which collapses into Approach B.
It's also GitHub-only.
- **Approach B — a registry-managed grants table** (OIDC bootstrap, or
device-flow admin check). The most capable and provider-agnostic option,
and probably where v1 wants to go. But it introduces exactly the
"registry manages an authorization database" layer we wanted to avoid
taking on right now: revocation, sync, audit, migration.
- **Approach C — scoped bearer tokens (npm-style).** Good ergonomics,
but again implies issuance/storage the registry would own.
The two-property test (does the registry control the decision? is it
granted through an act requiring real authority?) is the right lens.
This change satisfies it **without** new state: the registry makes the
decision (it filters on role), and the authority is real (live GitHub
Owner role, re-checked on every short-lived token exchange).
**What this deliberately gives up**, so reviewers can weigh it honestly:
- **Owners are always in the loop.** Only org Owners can publish org
servers; there's no delegated "this team can publish this server" — that
needs Approach B's state. Reduced flexibility in exchange for zero new
infrastructure.
- **Blast radius within an org is unchanged.** An Owner (or Owner-scoped
CI token) can still overwrite *any* server under the org namespace,
because there's still no per-server publisher ownership. That
hijack-an-existing-server problem is real but **orthogonal** to this fix
and belongs in its own change (record publisher identity per server;
enforce it on update) — a follow-up to take alongside the OIDC hardening
below.
- **OIDC is untouched and remains coarser.** The `github-oidc` path
still grants the whole `io.github.<owner>/*` namespace to any workflow
with `id-token: write`, i.e. effectively anyone with write access to any
repo in the org, and it excludes non-Actions CI (Jenkins/GitLab can't
mint GitHub Actions OIDC). The admin-PAT path here is the
higher-assurance option for org publishing; OIDC stays as a
lower-assurance Actions convenience to be tightened separately.
## Revocation
The registry JWT is **5-minute, no-refresh** (per #264/#273), so loss of
Owner status propagates within minutes on the next token exchange, with
no revocation list to maintain.
## Tests
`go test ./internal/api/handlers/v0/auth/...` passes, including:
- member-role org is **not** granted; only admin orgs are
- a missing-scope `403` (no `read:org`) still yields the personal
namespace and no error
- an admin org on a **later page** of memberships is still granted
(pagination correctness)
- a `5xx` from the memberships call **fails closed** (no token issued)
rather than degrading to personal-only
- a rate-limit `403` (`X-RateLimit-Remaining: 0` / `Retry-After`)
**fails closed** — not mistaken for a missing-scope `403`
- existing org/name-validation tests updated to the new endpoint + role
shape
`gofmt`/`go vet`/`golangci-lint` (CI-pinned v2.11.4) clean; CI green on
all checks.
## Live verification
Confirmed end-to-end against real `api.github.com` (not just mocks) by
exercising this branch's `ExchangeToken` and decoding the `permissions`
claim of the returned JWT.
A dedicated org, **Tadasant Test Org** (login `Tadasant-Test-Org`), is
Owned by one account and has a second account joined as a plain
**member**. Both memberships are `active`, verified via the same
endpoint the fix uses (`GET /user/memberships/orgs/{org}`):
| Token (role) | `io.github.Tadasant-Test-Org/*` granted? | Other
patterns granted |
|---|---|---|
| Owner (`admin`) | ✅ yes | personal `io.github.<owner>/*` |
| member | ❌ no | personal `io.github.<member>/*` + the orgs that
account actually Owns |
The member case is the meaningful one: that membership is **active and
returned** by `GET /user/memberships/orgs`, and is excluded purely
because its role is `member`, not `admin`. Under the previous `GET
/users/{username}/orgs` behavior (membership = authority, no role), the
same active membership **would have granted** the org namespace. The
role filter is also selective rather than blanket-deny — the member
account still receives the namespaces of the orgs where it genuinely
holds Owner.
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Radoslav Dimitrov <radoslav@stacklok.com>
Bumps
[github.com/pulumi/pulumi/sdk/v3](https://github.com/pulumi/pulumi) from
3.248.0 to 3.251.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pulumi/pulumi/releases">github.com/pulumi/pulumi/sdk/v3's
releases</a>.</em></p>
<blockquote>
<h2>v3.251.0</h2>
<h2>3.251.0 (2026-07-08)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>[cli] Show a <code>retain</code> marker for retain-on-delete
resources in <code>--diff</code> output <a
href="https://redirect.github.com/pulumi/pulumi/pull/23754">#23754</a></li>
<li>[cli] Don't miscopy out archives <a
href="https://redirect.github.com/pulumi/pulumi/pull/23798">#23798</a></li>
</ul>
<h3>Miscellaneous</h3>
<ul>
<li>[cli] Add <code>pulumi neo --debug-update</code> and <code>pulumi
neo --debug-preview</code> flags to investigate a failed update or
preview, suggested in the failure output <a
href="https://redirect.github.com/pulumi/pulumi/pull/23499">#23499</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli/convert] Add an <code>ecosystem</code> field to converter
mapping requests so a converter can request mappings for the ecosystem
it consumes rather than its own name <a
href="https://redirect.github.com/pulumi/pulumi/pull/23804">#23804</a></li>
<li>[cli/deployment] <code>pulumi deployment settings</code> no longer
writes the local <code>Pulumi.<stack>.deploy.yaml</code> file: the
experimental <code>init</code>, <code>pull</code>,
<code>configure</code>, and <code>env</code> subcommands have been
removed, and the CLI no longer calls the deployment-settings encrypt
endpoint. <code>get</code>/<code>edit</code>/<code>destroy</code>
continue to manage settings directly in Pulumi Cloud <a
href="https://redirect.github.com/pulumi/pulumi/pull/23480">#23480</a></li>
<li>[cli/deployment] The deployment settings file
(<code>Pulumi.<stack>.deploy.yaml</code>) has been removed
entirely. The experimental <code>pulumi deployment settings push</code>
(<code>update</code>/<code>up</code>) command, the
<code>--config-file</code> flag, and the SDK helpers that read the file
have been removed. Manage deployment settings directly in Pulumi Cloud
with <code>pulumi deployment settings get</code>, <code>edit</code>, and
<code>destroy</code> <a
href="https://redirect.github.com/pulumi/pulumi/pull/23480">#23480</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[cli/display] Prevent plugin debug logs from appearing as raw JSON
in the CLI's output when logging with <code>--logtostderr</code> <a
href="https://redirect.github.com/pulumi/pulumi/pull/23633">#23633</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli/env] Report the new revision number when an environment
definition is updated (e.g. <code>pulumi env edit</code>, <code>pulumi
env provider</code>, <code>pulumi env version rollback</code>) <a
href="https://redirect.github.com/pulumi/pulumi/pull/23799">#23799</a></li>
</ul>
<h3>Miscellaneous</h3>
<ul>
<li>[cli/env] Fold the Pulumi ESC engine and CLI into the pulumi/pulumi
monorepo, removing the sdk↔esc Go module cycle. Internal refactor with
no user-facing behavior change; <code>pulumi env</code>/<code>pulumi
esc</code> are unaffected. <a
href="https://redirect.github.com/pulumi/pulumi/pull/23746">#23746</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli/import] Support importing resources under parameterized
providers from a converter or import file <a
href="https://redirect.github.com/pulumi/pulumi/pull/23763">#23763</a></li>
<li>[cli/import] Support importing resources under
extension-parameterized providers <a
href="https://redirect.github.com/pulumi/pulumi/pull/23779">#23779</a></li>
</ul>
<h3>Features</h3>
<ul>
<li>[engine] Add <code>TargetSnippets</code> to deployment options to
target snippets by UUID. <a
href="https://redirect.github.com/pulumi/pulumi/pull/23745">#23745</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[engine] Add OpenTelemetry spans to the StackReference read path so
performance traces can pinpoint slow snapshot fetches, deserialization,
or secret decryption <a
href="https://redirect.github.com/pulumi/pulumi/pull/23787">#23787</a></li>
</ul>
<h3>Features</h3>
<ul>
<li>[programgen/pcl] Invoke functions declared with multi-argument
inputs using positional arguments in PCL <a
href="https://redirect.github.com/pulumi/pulumi/pull/23571">#23571</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[sdk/nodejs] Don't include the version in module paths when
serializing functions when using pnpm <a
href="https://redirect.github.com/pulumi/pulumi/pull/23767">#23767</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pulumi/pulumi/blob/master/CHANGELOG.md">github.com/pulumi/pulumi/sdk/v3's
changelog</a>.</em></p>
<blockquote>
<h2>3.251.0 (2026-07-08)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>[cli] Show a <code>retain</code> marker for retain-on-delete
resources in <code>--diff</code> output <a
href="https://redirect.github.com/pulumi/pulumi/pull/23754">#23754</a></li>
<li>[cli] Don't miscopy out archives <a
href="https://redirect.github.com/pulumi/pulumi/pull/23798">#23798</a></li>
</ul>
<h3>Miscellaneous</h3>
<ul>
<li>[cli] Add <code>pulumi neo --debug-update</code> and <code>pulumi
neo --debug-preview</code> flags to investigate a failed update or
preview, suggested in the failure output <a
href="https://redirect.github.com/pulumi/pulumi/pull/23499">#23499</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli/convert] Add an <code>ecosystem</code> field to converter
mapping requests so a converter can request mappings for the ecosystem
it consumes rather than its own name <a
href="https://redirect.github.com/pulumi/pulumi/pull/23804">#23804</a></li>
<li>[cli/deployment] <code>pulumi deployment settings</code> no longer
writes the local <code>Pulumi.<stack>.deploy.yaml</code> file: the
experimental <code>init</code>, <code>pull</code>,
<code>configure</code>, and <code>env</code> subcommands have been
removed, and the CLI no longer calls the deployment-settings encrypt
endpoint. <code>get</code>/<code>edit</code>/<code>destroy</code>
continue to manage settings directly in Pulumi Cloud <a
href="https://redirect.github.com/pulumi/pulumi/pull/23480">#23480</a></li>
<li>[cli/deployment] The deployment settings file
(<code>Pulumi.<stack>.deploy.yaml</code>) has been removed
entirely. The experimental <code>pulumi deployment settings push</code>
(<code>update</code>/<code>up</code>) command, the
<code>--config-file</code> flag, and the SDK helpers that read the file
have been removed. Manage deployment settings directly in Pulumi Cloud
with <code>pulumi deployment settings get</code>, <code>edit</code>, and
<code>destroy</code> <a
href="https://redirect.github.com/pulumi/pulumi/pull/23480">#23480</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[cli/display] Prevent plugin debug logs from appearing as raw JSON
in the CLI's output when logging with <code>--logtostderr</code> <a
href="https://redirect.github.com/pulumi/pulumi/pull/23633">#23633</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli/env] Report the new revision number when an environment
definition is updated (e.g. <code>pulumi env edit</code>, <code>pulumi
env provider</code>, <code>pulumi env version rollback</code>) <a
href="https://redirect.github.com/pulumi/pulumi/pull/23799">#23799</a></li>
</ul>
<h3>Miscellaneous</h3>
<ul>
<li>[cli/env] Fold the Pulumi ESC engine and CLI into the pulumi/pulumi
monorepo, removing the sdk↔esc Go module cycle. Internal refactor with
no user-facing behavior change; <code>pulumi env</code>/<code>pulumi
esc</code> are unaffected. <a
href="https://redirect.github.com/pulumi/pulumi/pull/23746">#23746</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli/import] Support importing resources under parameterized
providers from a converter or import file <a
href="https://redirect.github.com/pulumi/pulumi/pull/23763">#23763</a></li>
<li>[cli/import] Support importing resources under
extension-parameterized providers <a
href="https://redirect.github.com/pulumi/pulumi/pull/23779">#23779</a></li>
</ul>
<h3>Features</h3>
<ul>
<li>[engine] Add <code>TargetSnippets</code> to deployment options to
target snippets by UUID. <a
href="https://redirect.github.com/pulumi/pulumi/pull/23745">#23745</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[engine] Add OpenTelemetry spans to the StackReference read path so
performance traces can pinpoint slow snapshot fetches, deserialization,
or secret decryption <a
href="https://redirect.github.com/pulumi/pulumi/pull/23787">#23787</a></li>
</ul>
<h3>Features</h3>
<ul>
<li>[programgen/pcl] Invoke functions declared with multi-argument
inputs using positional arguments in PCL <a
href="https://redirect.github.com/pulumi/pulumi/pull/23571">#23571</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[sdk/nodejs] Don't include the version in module paths when
serializing functions when using pnpm <a
href="https://redirect.github.com/pulumi/pulumi/pull/23767">#23767</a></li>
<li>[sdk/nodejs] Support pnpm 11 <a
href="https://redirect.github.com/pulumi/pulumi/pull/23815">#23815</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="aff0ffa2cc"><code>aff0ffa</code></a>
do: fix <code>--dry-run</code> for delete (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23809">#23809</a>)</li>
<li><a
href="c9a87908cd"><code>c9a8790</code></a>
Add pulumi neo debug command (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23499">#23499</a>)</li>
<li><a
href="4a79549ecd"><code>4a79549</code></a>
Invoke multi-argument-input functions positionally in PCL (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23571">#23571</a>)</li>
<li><a
href="3212152920"><code>3212152</code></a>
do: make default input YAML (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23808">#23808</a>)</li>
<li><a
href="93ab9680c5"><code>93ab968</code></a>
Add an ecosystem to converter mapping requests (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23804">#23804</a>)</li>
<li><a
href="82c4164562"><code>82c4164</code></a>
do: align prompting with up/destroy (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23805">#23805</a>)</li>
<li><a
href="3ec25324d4"><code>3ec2532</code></a>
Update actions/download-artifact action to v8 (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23793">#23793</a>)</li>
<li><a
href="5e1b1d0903"><code>5e1b1d0</code></a>
Add more tracing spans around stack references (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23787">#23787</a>)</li>
<li><a
href="45b7ec7e17"><code>45b7ec7</code></a>
do: improve usage section (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23782">#23782</a>)</li>
<li><a
href="54b4e80e49"><code>54b4e80</code></a>
Don't include the version in module paths when serializing functions
when usi...</li>
<li>Additional commits viewable in <a
href="https://github.com/pulumi/pulumi/compare/v3.248.0...v3.251.0">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.37.0 to
0.38.0.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="792ac169a9"><code>792ac16</code></a>
go.mod: update golang.org/x dependencies</li>
<li><a
href="fe2ec04f7c"><code>fe2ec04</code></a>
all: fix some comments to improve readability</li>
<li>See full diff in <a
href="https://github.com/golang/mod/compare/v0.37.0...v0.38.0">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Summary
We keep getting PRs (e.g. #1385, #1368, #1367, #1363, #1354) that try to
"publish" an MCP server by adding files under `servers/` or editing
`data/seed.json`. That isn't how publishing works — servers are
published with the `mcp-publisher` CLI against the live registry API.
This adds automation that detects those PRs, comments with a pointer to
the publishing quickstart, labels them `invalid`, and closes them.
## How it works (two stages, no `pull_request_target`)
`pull_request_target` is intentionally avoided. Instead:
- **Stage 1 — `detect-invalid-publish-prs.yml`** runs on `pull_request`
(opened/reopened) with a **read-only** token. It only reads the changed
file paths and, if the PR *exclusively* touches `servers/**` and/or
`data/seed.json` (and the author isn't a MEMBER/OWNER/COLLABORATOR),
records just the PR number as a short-lived artifact. It can't comment
or close anything.
- **Stage 2 — `close-invalid-publish-prs.yml`** runs via `workflow_run`
in the trusted base-repo context (write token). It picks up the flagged
PR number, **independently re-validates** the PR from the API (still
open, external author, files still match, not already labeled), then
comments, labels `invalid`, and closes.
### Trust boundary
The only thing crossing from the untrusted stage to the privileged stage
is the **PR number**, sanitized to digits only. Stage 2 never trusts
stage 1's verdict — it re-derives every decision. Neither stage ever
checks out or runs PR code.
### Safety against false positives
- Fires only when a PR touches *exclusively* `servers/**` and/or
`data/seed.json` — a real code PR that also happens to touch seed data
is left alone.
- Skips `MEMBER`/`OWNER`/`COLLABORATOR` authors, so maintainers editing
dev seed data aren't auto-closed.
- Idempotent: skips PRs already labeled `invalid` (e.g. if a maintainer
reopens one).
## Notes
- Like any `pull_request`/`workflow_run` automation, this only takes
effect **once merged to `main`** — it is not retroactive and won't run
on this PR. The currently-open offending PRs should be closed manually.
- Pinned action SHAs match the repo's existing convention
(`upload-artifact` reuses the SHA already in `ci.yml`).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Summary:
- Fix the reference index FAQ link to point at the existing docs FAQ.
- Correct package registry guide links from docs/contributing into
docs/reference.
Validation:
- Focused markdown-link-check on the changed docs passed.
- Git whitespace check passed.
Co-authored-by: kriptoburak <kriptoburak@users.noreply.github.com>
Bumps [github.com/coreos/go-oidc/v3](https://github.com/coreos/go-oidc)
from 3.18.0 to 3.19.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/coreos/go-oidc/releases">github.com/coreos/go-oidc/v3's
releases</a>.</em></p>
<blockquote>
<h2>v3.19.0</h2>
<h2>What's Changed</h2>
<ul>
<li>fix: Key refresh should set <code>no-cache</code> to get most up to
date keys by <a
href="https://github.com/Yanni8"><code>@Yanni8</code></a> in <a
href="https://redirect.github.com/coreos/go-oidc/pull/485">coreos/go-oidc#485</a></li>
<li>oidc: add support for validating back-channel logout tokens by <a
href="https://github.com/ericchiang"><code>@ericchiang</code></a> in <a
href="https://redirect.github.com/coreos/go-oidc/pull/486">coreos/go-oidc#486</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Yanni8"><code>@Yanni8</code></a> made
their first contribution in <a
href="https://redirect.github.com/coreos/go-oidc/pull/485">coreos/go-oidc#485</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/coreos/go-oidc/compare/v3.18.0...v3.19.0">https://github.com/coreos/go-oidc/compare/v3.18.0...v3.19.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4204f0b2b0"><code>4204f0b</code></a>
oidc: add support for validating back-channel logout tokens</li>
<li><a
href="f77e01c509"><code>f77e01c</code></a>
fix: Key refresh should set no-cache to get most up to date keys</li>
<li>See full diff in <a
href="https://github.com/coreos/go-oidc/compare/v3.18.0...v3.19.0">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps
[github.com/pulumi/pulumi/sdk/v3](https://github.com/pulumi/pulumi) from
3.244.0 to 3.248.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pulumi/pulumi/releases">github.com/pulumi/pulumi/sdk/v3's
releases</a>.</em></p>
<blockquote>
<h2>v3.248.0</h2>
<h2>3.248.0 (2026-06-24)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>[cli] Fix a panic in <code>pulumi package get-schema</code> when
binding a schema that references an uninstalled plugin <a
href="https://redirect.github.com/pulumi/pulumi/pull/23647">#23647</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli] Add options to <code>pulumi stack get</code> for parity with
bare <code>pulumi stack</code> <a
href="https://redirect.github.com/pulumi/pulumi/pull/23623">#23623</a></li>
<li>[cli] Add <code>--output</code> flag to about and whoami commands <a
href="https://redirect.github.com/pulumi/pulumi/pull/23651">#23651</a></li>
</ul>
<h3>Features</h3>
<ul>
<li>[engine] Add support for 'snippets', blocks of PCL kept in state to
track ad-hoc resources <a
href="https://redirect.github.com/pulumi/pulumi/pull/23286">#23286</a></li>
<li>[engine] Send the address of a schema loader service to resource
providers as part of the provider handshake <a
href="https://redirect.github.com/pulumi/pulumi/pull/23645">#23645</a></li>
<li>[engine] Send the address of a package resolver service to resource
providers as part of the provider handshake <a
href="https://redirect.github.com/pulumi/pulumi/pull/23654">#23654</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[programgen] Guard references to conditionally-created (boolean
<code>range</code>) resources in generated Python and NodeJS programs so
they type-check <a
href="https://redirect.github.com/pulumi/pulumi/pull/23634">#23634</a></li>
<li>[programgen] Generate map <code>range</code> resource collections as
key-indexed maps in Python and NodeJS so they can be indexed by key <a
href="https://redirect.github.com/pulumi/pulumi/pull/23639">#23639</a></li>
</ul>
<h3>Features</h3>
<ul>
<li>[sdk/nodejs] Add <code>Output.recover</code> to catch and recover
from exceptions in outputs <a
href="https://redirect.github.com/pulumi/pulumi/pull/23642">#23642</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[sdkgen] Fix extra trailing new lines in comments <a
href="https://redirect.github.com/pulumi/pulumi/pull/23619">#23619</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[sdkgen] Require callers to pass an explicit schema loader when
binding PCL programs and package schemas <a
href="https://redirect.github.com/pulumi/pulumi/pull/23672">#23672</a></li>
</ul>
<h2>v3.247.0</h2>
<h2>3.247.0 (2026-06-18)</h2>
<h3>Features</h3>
<ul>
<li>[cli/config] Add --raw flag to <code>pulumi config set</code> to
avoid stripping newlines when input is piped through stdin <a
href="https://redirect.github.com/pulumi/pulumi/pull/23593">#23593</a></li>
<li>[cli/do] Add <code>--provider</code> flag to pull provider config to
use from existing provider state <a
href="https://redirect.github.com/pulumi/pulumi/pull/23560">#23560</a></li>
<li>[cli/engine] Resource providers now receive the active login's API
address and access token through PULUMI_API and PULUMI_ACCESS_TOKEN <a
href="https://redirect.github.com/pulumi/pulumi/pull/23589">#23589</a></li>
<li>[cli/neo] Add a <code>--disable-integrations</code> flag to
<code>pulumi neo</code> that runs the task with no integration
credentials <a
href="https://redirect.github.com/pulumi/pulumi/pull/23531">#23531</a></li>
<li>[engine] Send the address of a mapper service to resource providers
as part of the provider handshake</li>
<li>[programgen/go] Support functions with multiArgumentInputs <a
href="https://redirect.github.com/pulumi/pulumi/pull/23554">#23554</a></li>
<li>[programgen/python] Support functions with multiArgumentInputs <a
href="https://redirect.github.com/pulumi/pulumi/pull/23574">#23574</a></li>
<li>[sdk/nodejs] Registered resources can now be retrieved from the mock
monitor for test assertions <a
href="https://redirect.github.com/pulumi/pulumi/pull/20539">#20539</a></li>
<li>[sdk/python] Add <code>Output.recover</code> to catch and recover
from exceptions in outputs <a
href="https://redirect.github.com/pulumi/pulumi/pull/23591">#23591</a></li>
<li>[sdkgen] Adds support for language agnostic cross references in
schemas. Use the form <code>{{% ref <target> %}}</code> to
reference other schema components in markdown descriptions. Such as `{{%
ref <a
href="https://redirect.github.com/pulumi/pulumi/pull/21369">#21369</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pulumi/pulumi/blob/master/CHANGELOG.md">github.com/pulumi/pulumi/sdk/v3's
changelog</a>.</em></p>
<blockquote>
<h2>3.248.0 (2026-06-24)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>[cli] Fix a panic in <code>pulumi package get-schema</code> when
binding a schema that references an uninstalled plugin <a
href="https://redirect.github.com/pulumi/pulumi/pull/23647">#23647</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli] Add options to <code>pulumi stack get</code> for parity with
bare <code>pulumi stack</code> <a
href="https://redirect.github.com/pulumi/pulumi/pull/23623">#23623</a></li>
<li>[cli] Add <code>--output</code> flag to about and whoami commands <a
href="https://redirect.github.com/pulumi/pulumi/pull/23651">#23651</a></li>
</ul>
<h3>Features</h3>
<ul>
<li>[engine] Add support for 'snippets', blocks of PCL kept in state to
track ad-hoc resources <a
href="https://redirect.github.com/pulumi/pulumi/pull/23286">#23286</a></li>
<li>[engine] Send the address of a schema loader service to resource
providers as part of the provider handshake <a
href="https://redirect.github.com/pulumi/pulumi/pull/23645">#23645</a></li>
<li>[engine] Send the address of a package resolver service to resource
providers as part of the provider handshake <a
href="https://redirect.github.com/pulumi/pulumi/pull/23654">#23654</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[programgen] Guard references to conditionally-created (boolean
<code>range</code>) resources in generated Python and NodeJS programs so
they type-check <a
href="https://redirect.github.com/pulumi/pulumi/pull/23634">#23634</a></li>
<li>[programgen] Generate map <code>range</code> resource collections as
key-indexed maps in Python and NodeJS so they can be indexed by key <a
href="https://redirect.github.com/pulumi/pulumi/pull/23639">#23639</a></li>
</ul>
<h3>Features</h3>
<ul>
<li>[sdk/nodejs] Add <code>Output.recover</code> to catch and recover
from exceptions in outputs <a
href="https://redirect.github.com/pulumi/pulumi/pull/23642">#23642</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>[sdkgen] Fix extra trailing new lines in comments <a
href="https://redirect.github.com/pulumi/pulumi/pull/23619">#23619</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[sdkgen] Require callers to pass an explicit schema loader when
binding PCL programs and package schemas <a
href="https://redirect.github.com/pulumi/pulumi/pull/23672">#23672</a></li>
</ul>
<h2>3.247.0 (2026-06-18)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>[cli] Ensure <code>pulumi logout</code> clears the current tokenless
backend in coding agent environments <a
href="https://redirect.github.com/pulumi/pulumi/pull/23540">#23540</a></li>
<li>[cli] Read Git metadata correctly in repositories that enable the
worktreeConfig extension, such as those hosted on Azure DevOps <a
href="https://redirect.github.com/pulumi/pulumi/pull/23535">#23535</a></li>
</ul>
<h3>Improvements</h3>
<ul>
<li>[cli] Respect PULUMI_SKIP_CONFIRMATIONS whenever we ask for
confirmation <a
href="https://redirect.github.com/pulumi/pulumi/pull/23607">#23607</a></li>
<li>[cli] Use list and remove as the canonical names for list/remove
commands, with ls and rm as aliases <a
href="https://redirect.github.com/pulumi/pulumi/pull/23608">#23608</a></li>
</ul>
<h3>Features</h3>
<ul>
<li>[cli/config] Add --raw flag to <code>pulumi config set</code> to
avoid stripping newlines when input is piped through stdin <a
href="https://redirect.github.com/pulumi/pulumi/pull/23593">#23593</a></li>
</ul>
<h3>Bug Fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a88168d865"><code>a88168d</code></a>
[programgen] Generate map ranges as key-indexed collections (Python
& NodeJS)...</li>
<li><a
href="3263e4ae48"><code>3263e4a</code></a>
Bump language versions (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23685">#23685</a>)</li>
<li><a
href="a95f24c34b"><code>a95f24c</code></a>
Bump the Pulumi HCL version to 0.8.0 (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23679">#23679</a>)</li>
<li><a
href="91f59ddad4"><code>91f59dd</code></a>
Require an explicit schema loader when binding programs and specs (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23672">#23672</a>)</li>
<li><a
href="35eb97386d"><code>35eb973</code></a>
Actually set an input in TestRefreshBeforeUpdateDeletedResource (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23681">#23681</a>)</li>
<li><a
href="9fd06c1f63"><code>9fd06c1</code></a>
Send a resolver target to providers during handshake (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23654">#23654</a>)</li>
<li><a
href="10914919a6"><code>1091491</code></a>
Start changing PolicyRemediationEvent to property.Map (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23667">#23667</a>)</li>
<li><a
href="e2cca27c77"><code>e2cca27</code></a>
[programgen] Guard references to conditionally-created resources (Python
& No...</li>
<li><a
href="109f27fb39"><code>109f27f</code></a>
NodeJS recover method (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23642">#23642</a>)</li>
<li><a
href="facc18efca"><code>facc18e</code></a>
Send a loader target to providers during handshake (<a
href="https://redirect.github.com/pulumi/pulumi/issues/23645">#23645</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/pulumi/pulumi/compare/v3.244.0...v3.248.0">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Summary
Fixes the information-disclosure regression introduced by #1335 (item 1
of #1337).
`ListServersError` passed the raw `err` into
`huma.Error500InternalServerError(...)`. huma serializes extra error
args into the response body's `errors` array (`ErrorModel.Errors`,
`json:"errors,omitempty"`), so on the **public, unauthenticated** `GET
/v0/servers` endpoint a genuine DB failure echoed the internal wrapped
error from `internal/database/postgres.go` (`error iterating rows: <pgx
error>`) back to the client. pgx/pgconn errors can carry SQLSTATE codes,
constraint/table/column names, and internal messages (CWE-209).
## Change
- Drop `err` from the 500 call so only the generic message is returned;
keep `log.Printf` for the server-side detail — matching the sibling
handlers (`servers.go:190/220`, `edit.go`, `status.go`).
- Add a regression test
(`TestListServersError_realFailureDoesNotLeakDetail`) that marshals the
500 error and asserts the internal detail is absent from the
client-visible body. Existing tests only asserted status codes, which is
why the leak slipped through.
The 499 client-cancelled path is unchanged (the client has already
disconnected, so nothing is leaked there).
## Test plan
- [x] `go test ./internal/api/handlers/v0/... -run ListServersError`
(3/3 pass)
- [x] `go build ./...`, `go vet`, `golangci-lint` (no new findings in
changed files)
## Note
This leaves the non-security items in #1337 (correcting the `superfluous
WriteHeader` claim, `statusClientClosed` const reuse, broader
cancellation-guard scope) for separate follow-up. Closing #1337 here
since the only security-impacting item is addressed; reopen/split if
you'd prefer to track the nits independently.
Closes#1337🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>