Changelog
✨ Features
• b771c0541b03d42adaa09dc83ff3c350a8bf9631:feat!: remove what v2 deprecated, minus the one window that never opened (#641) (@jmrplens)
• e9626dfda03695a6e367a8450f94eab3c9f7a858:feat(achievements): take the avatar upload, and judge the GraphQL documents that carry a file (#592) (@jmrplens)
• 0664a2861ec3beff7f07f369735f43c6debbb86d:feat(apiexposes): pin the condition GitLab sends each REST entity field under (#622) (@jmrplens)
• 73b04d36a9d15593c403764d14c742420708f3de:feat(audit): add R-PATH, the dimension that reads the request rather than the surface (#598) (@jmrplens)
• bf04b7714cf6cf2f2830133e02ccd480c77f964f:feat(audit): ask a booted GitLab what its own REST API is (#650) (@jmrplens)
• d6993c06e5ec0fe37ad6a03dcee76846fc734cb8:feat(audit): ask the sent question of GraphQL, where nothing asked it (#648) (@jmrplens)
• 0b23a9e474b0e7dc2f3921c0247b75213a0aad94:feat(audit): check the prose a meta-tool serves against the parameters it takes (#590) (@jmrplens)
• f8f8f9c51504d49abff33a2b0c3df8276031ecbf:feat(audit): judge every GraphQL decoder against the document it decodes (#621) (@jmrplens)
• ca4d86a2755d01a2d62ace3c825961e9a7c444e6:feat(audit): pin what GitLab says its own API returns, from the document GitLab generates (#599) (@jmrplens)
• de07060d299752e5cf3e3bc4642699f5252e3ffa:feat(audit): read the SDK's enum values instead of trusting the field (#527) (@jmrplens)
• be21f5e7098ca6a23305036f37dbf81e6e1fe4d6:feat(audit): report the output fields GitLab's own document says it does not send (#585) (@jmrplens)
• b62edb0e066e8dda9f81fb9eddab800f2669d589:feat(audit): say which sent findings belong upstream in client-go (#654) (@jmrplens)
• b244e4149b961f84203beb2271b335caad4088b0:feat(audit_1to1): ask the shape check at type grain, and adjudicate what it found (#589) (@jmrplens)
• cb452bd5b31f367425a161a795c1ad60f059ec83:feat(bench): measure and publish what the server costs to run (#463) (@jmrplens)
• 80245f6d4b89d86249165c16ebd6a8d574b3b961:feat(bench): measure whether a bound leaves the quiet tenant better off (#597) (@jmrplens)
• 5492f2b51f6434e5a388d580f7b831cdb2672661:feat(bench): step one process up to a thousand credentials, with a profile at every step (#534) (@jmrplens)
• b2c4bdd523f8288e55fe98f47a7905aba23509d3:feat(catalog): declare the documented value sets as schema enums (#494) (@jmrplens)
• 13371b538326547143fe0387a18f5198d274fd8b:feat(catalog): embed the canonical resource of every get action again (#503) (@jmrplens)
• 735329de6c55074ec76cb7778168d74ff283b6ac:feat(config): prefix every server variable with GITLAB_MCP_, the GITLAB_ switches included (#523) (@jmrplens)
• 124f103b09e83cc9286947b2cb330233697ef03c:feat(dependencyfirewall): expose the Dependency Firewall evaluate endpoint (#451) (@jmrplens)
• 36089b8d750f2898bec3894bdd802eae2ff32b84:feat(epics): expose what the Work Items API offers an epic, and publish only what GitLab sends (#593) (@jmrplens)
• 764a12fd016410772465a6e45b35d8d89df0fbe5:feat(gen_testing_docs): pass -timeout through, refresh testing.md, gate it in CI (#441) (@jmrplens)
• 1c5edb74470a17a98af4776c056b478521625859:feat(geo): publish what a Geo site and its status send, declare the matrix (#665) (@jmrplens)
• 6befc450256254b2d1b10727d4762b68bc6c905b:feat(gitlab): read a field client-go does not model from the captured response (#625) (@jmrplens)
• 677e1dbf53eaa0e1638da772690d534857e56b5f:feat(graphql): judge every document against the schema an instance serves today (#579) (@jmrplens)
• 476f7ad74a057e6c78062c91492a5a89c5456d24:feat(graphql): make the mocks refuse what GitLab refuses, and fix the nine tools that proved (#575) (@jmrplens)
• 04e528414424db9835931491f40047fcfc2fc90b:feat(http): believe the client-address header only from listed proxies (#480) (@jmrplens)
• 97132dc33328e162b0fb7a6d75e7c07bf389bfd1:feat(http): meter tools/list on a bucket of its own (#566) (@jmrplens)
• e5402d301beda45e8150d7ccdc2b866350d773f6:feat(http): report draining on /health and fingerprint the served configuration (#487) (@jmrplens)
• f34c38a51be98c1938b9ed7f9d559131fe7071d6:feat(members): read what client-go's member structs do not carry off the captured response (#628) (@jmrplens)
• 57bfc35f12cff2ed7e67395ecd92e19b0e65e5ef:feat(mergerequests): publish 15 fields and declare 34 the server never asks for (#668) (@jmrplens)
• 6a334cc98778a20b0e3a7cf2895e1b27305ae0b9:feat(notes): read what client-go does not model off the captured response, and publish only what GitLab sends (#626) (@jmrplens)
• 397c61ad4723f7f8a5941acb490a15c560f68580:feat(npm): install via npx with a per-platform binary wrapper (#323) (@jmrplens)
• 22e7650e69f8ff950361ffaec30383ed248dc456:feat(release): harden the whole release chain for a definitive 2.7.6 (#326) (@jmrplens)
• 11a3a2edd5d2f06641d1fbb9607dbc047e93327b:feat(release): ship the server on NuGet as a .NET tool (#526) (@jmrplens)
• 87e8f3e689efa8a7218029baae6098722e250993:feat(security)!: confirm push-mirror creation and filter the catalog by token scope (#673) (@jmrplens)
• 67f63e5451e6e02039c2a3ba5f2244c4bfd027af:feat(security)!: refuse outbound destinations the operator did not choose (#676) (@jmrplens)
• 072ea7a3ef02738bb72c364a06c4b3302965e75a:feat(server): probe the listener the server actually has, as the image's health check (#481) (@jmrplens)
• ab686b91e6012704a6fd58be7b247e5770b08aa8:feat(serverpool): say which eviction happened, and bound watchers across the process (#577) (@jmrplens)
• 87334adc5a01331d3122b5ddfb402b48782d1790:feat(stdio): serve a read_api token the read-only surface, as HTTP does (#505) (@jmrplens)
• 81b6aacbc06074407ecdba6354a6b3f55549dc52:feat(surface): read the six response fields client-go declares no member for (#629) (@jmrplens)
• 7733804423c0229c27b667f862160c34688da811:feat(tokens): read the granular, impersonation and resource fields no token struct carries (#630) (@jmrplens)
• 679a1bd33d826496bc848e80cfef7dde49aa5a8d:feat(tooling): gate the Markdown escaping rule, and fix everything it found (#594) (@jmrplens)
• fcf3469591492da9c17c79a5ec5d797445953f3e:feat(tools): publish 15 member-family fields and declare 9 GitLab never sends (#664) (@jmrplens)
• b8f700151a32f3b8e50103ed679b58af02a9b002:feat(tools): publish 36 fields GitLab sends across six packages (#661) (@jmrplens)
• 04d222546becbc41d524f7709a73fbdef183f5cb:feat(tools): publish the tail of the fields GitLab sends and we dropped (#656) (@jmrplens)
• 03a11e3e38cbfd8147871182f954c650c618ec58:feat(users): publish 45 fields and declare 19 the route set cannot send (#670) (@jmrplens)
• bc47d37cadc246b983ed999edcaf085fb2f3633f:feat(workitems): expose every filter and widget client-go carries, and the objects behind them (#591) (@jmrplens)
• cd541e9176553ea36bd27e6e067983d23eddf29d:feat: update client-go to v2.64.0 and expose the achievements service it brought (#560) (@jmrplens)
🐛 Bug Fixes
• a3dcafcccd1a774223503e33892b0e72dba222d5:fix(audit): compare against an SDK struct that tags nothing, instead of reporting all of it as ours (#582) (@jmrplens)
• 0adc6f0a7de2cfcfe3646c548ba70c405226f83c:fix(audit): judge a type named as a field when a converter pairs it (#646) (@jmrplens)
• c4f60bb403f666933aa467621d28683fb6fea86f:fix(audit): read a merged Grape exposure as the keys it contributes (#655) (@jmrplens)
• 8c1df8cf8f5ddb2ff79014464f7af5abd13b3ae7:fix(audit_1to1): read a reopened Ruby class, promote embeds, nest through any struct, annotate per field (#623) (@jmrplens)
• f22a164991a14535c25977851669b12cf08f7b09:fix(bench): measure what a credential costs to hold, not only to serve (#544) (@jmrplens)
• 041bd0272541d3a44fb8c3a90b8afaa2ff03694b:fix(config): say 3.1.0, not v3, as the release that drops the old variable names (#680) (@jmrplens)
• 4f512cb61e0530d77aa4ef227dc4cc71a7c7f720:fix(e2e): build the dynamic catalog the way the server does, and read a preview as the error it is (#475) (@jmrplens)
• febc9600aeee3cf8379f70a9f8ac2e5bf7f62ee6:fix(epicissues): move the child under its parent the way GitLab accepts (#606) (@jmrplens)
• 9ec10204cb456096bf71f700dbb743dd2aa890ee:fix(eval): give the thirteen colliding evaluator cases their own identifiers (#433) (@jmrplens)
• 9c5cc8d56146c5eb4286829cd77a2a861a357237:fix(http): conform to the authorization and transport specifications, and refresh dependency pins (#328) (@jmrplens)
• 867be652e3d7b20074d7c4a2abd8446210a84c4f:fix(http): make the OAuth surface honest, and admit read-only credentials (#324) (@jmrplens)
• a64cc4437e8b502e109d3b70f59b09c2a978be7f:fix(http): refuse the free-instance hatch on a listener anyone can reach (#645) (@jmrplens)
• 0f08072df9270d76955318b4a37d9f3f76af115b:fix(markdown): size every hand-written code fence to its body, and gate the class (#677) (@jmrplens)
• 8d4e520751ad8908e2114d86af358cedaa88a171:fix(mcp): a tool call could kill the server, and subscriptions were dead by default (#334) (@jmrplens)
• acb3b16d98939f6f7077544f0f59f71e972bb6dc:fix(mcp): conform to the server-surface specifications (#333) (@jmrplens)
• 76c6aa1db4645df02f7496c868519df02d18abca:fix(mrapprovals): publish the four fields GitLab answers with, not the deprecated POST's twenty-four (#586) (@jmrplens)
• d4b0fdbc89090d18444fa5e69ae63a6d7aa0f1d9:fix(oauth): conform to the three authorization sub-pages, and keep the raw token out of the identity cache (#532) (@jmrplens)
• dc19efbeda4b24f0e412ebe45413477d89477c4c:fix(oauth): refuse unverified TLS, and stop calling an unadmitted token invalid (#331) (@jmrplens)
• 07b9e8693dba602e8858981370e6256acb8c7b4e:fix(oauth): serve the protected-resource document only on its derived path (#456) (@jmrplens)
• 32b25451e4b22ff17dcfa86be537acc58bbdf928:fix(pagination): page backwards where GitLab allows it, and stop advertising it where it does not (#595) (@jmrplens)
• 52841e96648e731309c7ce6cf6280c35d7abde71:fix(projects): answer a project with no push rules instead of dereferencing nil (#605) (@j