Skip to content

ci: Replace APIGurus as source for IT - #7774

Merged
Gavin Barron (gavinbarron) merged 9 commits into
microsoft:mainfrom
WolfgangHG:apigurus
Jul 20, 2026
Merged

Gavin Barron (gavinbarron) merged 9 commits into
microsoft:mainfrom
WolfgangHG:apigurus

Conversation

@WolfgangHG

Copy link
Copy Markdown
Contributor

This pull request contains the changes suggested in #7495: the OpenAPI specs hosted at APIGurus do not seem to be updated any longer. So pull the recent api specs from official sources where possible.

What do you think? Is this reasonable?

This makes sense in my opinion because it ensures that Kiota is compatible to the most recent version of commonly used APIs (e.g. Twitter). But it has the drawback that errors in the API might cause false errors in Kiota IT, and changes might require additional changes in Kiota.

I also checked the suppressions and exclusions and removed them if I could not reproduce the error (either fixed in a newer API version or a Kiota change resolved it). But maybe I removed too much, if e.g. the error reason was not meaningful enough. So, several tests might fail if this pull request performs the first CI run.
The linked issues in Ruby suppressions did not always make the actual error clear, so maybe I removed too much or the updated issue link does not point to the original error.

I also found one API that should ideally be pulled from Postman (#7495 (comment)), but this is not part of this pull request.

@WolfgangHG
Wolfgang Knauf (WolfgangHG) requested a review from a team as a code owner June 9, 2026 19:02

@baywet Vincent Biret (baywet) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution!

Comment thread it/config.json Resolved
@WolfgangHG

Copy link
Copy Markdown
Contributor Author

Hope I fixed the failing tests. I had not seen that "integration-tests.yml" and "idempotency-tests.yml" define the old api guru URLs for preloading.

@baywet
Vincent Biret (baywet) enabled auto-merge (squash) June 15, 2026 11:15
@baywet

Copy link
Copy Markdown
Member

Wolfgang Knauf (@WolfgangHG) I think something is off with artifacts download/upload and key composition. see https://github.com/microsoft/kiota/actions/runs/27542430722/job/81407904278
Would you mind having a look please?

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

Vincent Biret (@baywet) It seems the docusign json file was not download: https://github.com/microsoft/kiota/actions/runs/27542430722/job/81407737625 (Warning: No files were found with the provided path: it/openapi.yaml. No artifacts will be uploaded.) and thus no artifact was uploaded to the next step.
Actually, all http downloads failed. Do you have an idea?

@baywet

Copy link
Copy Markdown
Member

Wolfgang Knauf (@WolfgangHG) my guess is that this is not specific to this description, but instead this script is silently failing.

Invoke-WebRequest -Uri $descriptionUrl -OutFile $targetOpenapiPath

GitHub typically throttles unauthenticated requests much more than authenticated ones. Kiota automatically does retrial.
We might want to explore:

  • backoff and retry
  • optionally passing a token (from the workflow) to get higher throttling limits

Let me know if you have any additional comments or questions.

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

I think the Invoke-WebRequest prints error messages if something goes wrong. But I don't see anything in the output.

I could add diagnostic output to download-openapi-specs.ps1 and also test afterwards whether the file was written. What do you think?

@baywet

Copy link
Copy Markdown
Member

I've seen many instances where the output behaviour differs on PowerShell between the local and the GHA run environment. And you end up not "seeing" things. So yes, adding additional logging would be a good way to start.

auto-merge was automatically disabled June 15, 2026 18:10

Head branch was pushed to by a user without write access

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

I added several Write-Output / Write-Information to "download-openapi-specs.ps1" just to test whether I see any of them in the github log. They all will all be removed next time.

And I added

$ErrorActionPreference = "Stop"

...because when calling the script from a CMD window, the exit code (echo %errorlevel%) is "0" even if Invoke-WebRequest fails. But I wonder why I did not see an error output from this command.

Vincent Biret (@baywet) Could you start another CI run?

@WolfgangHG

Wolfgang Knauf (WolfgangHG) commented Jun 15, 2026 •

Copy link
Copy Markdown
Contributor Author

Rather obvious: the upload step always tried to upload "openapi.yaml", but with my changes, there could also be a "openapi.json". Shame on me that I did not see this before ;-). Now I try to upload both files - let's see what happens. Hope that the file is not present from a previous step. Maybe we should delete both files "openapi.json" and "openapi.yaml" in "download-openapi-specs.ps1".

Same fix should be applied to "integration-tests.yml".

And about logging: Write-Output works ;-). I will remove it when we have fixed CI.

Vincent Biret (@baywet) Another CI run please.

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

Seems the upload of both openapi.json and openapi.yaml in one step works.

New error happens in ./it/compare-generation.ps1 (https://github.com/microsoft/kiota/actions/runs/27572392069/job/81636616228), which always accessed "openapi.yaml" and thus failed with json files.

Vincent Biret (@baywet) I committed a fix, could you start CI again?

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

Another change: "get-description-artifact-key.ps1" always returned DESCRIPTION_PATH=./description/openapi.yaml.

Vincent Biret (@baywet) it is your turn again.

And all of this only because I changed "openapi.yaml" to "openapi.json" for json files (as part of the "default values" changes) - I considered it wrong to have a json file with wrong extension though this did not cause problems when invoking kiota ;-)

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

I think we make progress - this time most idempotency tests worked.

I applied the fix from "idempotency-tests.yml" also to "integration-tests.yml": after downloading the api description, try also to upload "openapi.json".

Vincent Biret (@baywet) One more time....

One of the failing idempotency tests seems to have run into a real error, maybe due to a newer api description..

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

Vincent Biret (@baywet) I digged through the idempotency tests. Here are the errors:

Problem 1:
idempotency (python, https://developers.notion.com/openapi.json)
https://github.com/microsoft/kiota/actions/runs/27618422969/job/81666134243

==>There was a change in file "models\partial_user_object_response.py":
First one:

@dataclass
class PartialUserObjectResponse(Parsable):
    """
    The user who created the data source.
    """

Second one:

@dataclass
class PartialUserObjectResponse(Parsable):
    """
    User who created the page.
    """

Maybe there was a change to the online api descriptions between test run 1 and 2. But this should not happen, as the test uses one single artifact that was downloaded before by this job: https://github.com/microsoft/kiota/actions/runs/27618422969/job/81665975879.
Do you see a point where the scripts might have fallen back to downloading api description (and picking a new one that was updating between first and second call) instead of using the artifact?


Problem 2:
idempotency (typescript, https://developers.notion.com/openapi.json)
https://github.com/microsoft/kiota/actions/runs/27618422969/job/81666131203

Error:
      System.InvalidOperationException: Namespace not found for return type
         at Kiota.Builder.Writers.TypeScript.CodeFunctionWriter.FindFunctionInNameSpace(String functionName, CodeElement codeElement, CodeType returnType) in ... kiota\src\Kiota.Builder\Writers\TypeScript\CodeFunctionWriter.cs:line 443
         at Kiota.Builder.Writers.TypeScript.CodeFunctionWriter.GetDeserializerFunctionName(CodeElement codeElement, CodeType returnType) in ... kiota\src\Kiota.Builder\Writers\TypeScript\CodeFunctionWriter.cs:line 436
         at Kiota.Builder.Writers.TypeScript.CodeFunctionWriter.WriteComposedTypeDeserializer(CodeFunction codeElement, LanguageWriter writer, CodeParameter composedParam, CodeFile codeFile) in ... kiota\src\Kiota.Builder\Writers\TypeScript\CodeFunctionWriter.cs:line 154
         at Kiota.Builder.Writers.TypeScript.CodeFunctionWriter.WriteDeserializerFunction(CodeFunction codeFunction, CodeFile codeFile, LanguageWriter writer) in ... kiota\src\Kiota.Builder\Writers\TypeScript\CodeFunctionWriter.cs:line 667
         at Kiota.Builder.Writers.TypeScript.CodeFunctionWriter.WriteCodeElement(CodeFunction codeElement, LanguageWriter writer) in ... kiota\src\Kiota.Builder\Writers\TypeScript\CodeFunctionWriter.cs:line 115
         at Kiota.Builder.Writers.LanguageWriter.Write[T](T code) in ... kiota\src\Kiota.Builder\Writers\LanguageWriter.cs:line 149
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCode(LanguageWriter writer, CodeElement element) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 83
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCode(LanguageWriter writer, CodeElement element) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 88
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToSingleFileAsync(LanguageWriter writer, CodeElement codeElement, String outputFile, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 35
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToSingleFileAsync(LanguageWriter writer, CodeElement codeElement, String outputFile, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 37
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToFilePerClassAsync(LanguageWriter writer, CodeNamespace currentNamespace, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 55
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToFilePerClassAsync(LanguageWriter writer, CodeNamespace currentNamespace, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 59
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToFilePerClassAsync(LanguageWriter writer, CodeNamespace currentNamespace, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 59
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToFilePerClassAsync(LanguageWriter writer, CodeNamespace currentNamespace, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 59
         at Kiota.Builder.KiotaBuilder.CreateLanguageSourceFilesAsync(GenerationLanguage language, CodeNamespace generatedCode, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\KiotaBuilder.cs:line 668
         at Kiota.Builder.KiotaBuilder.<>c__DisplayClass21_0.<<GenerateClientAsync>b__0>d.MoveNext() in ... kiota\src\Kiota.Builder\KiotaBuilder.cs:line 311
      --- End of stack trace from previous location ---
         at Kiota.Builder.KiotaBuilder.GenerateConsumerAsync(Func`5 innerGenerationSteps, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\KiotaBuilder.cs:line 348
         at Kiota.Builder.KiotaBuilder.GenerateConsumerAsync(Func`5 innerGenerationSteps, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\KiotaBuilder.cs:line 368
         at Kiota.Builder.KiotaBuilder.GenerateClientAsync(CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\KiotaBuilder.cs:line 285
         at kiota.Handlers.KiotaGenerateCommandHandler.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken) in ... kiota\src\kiota\Handlers\KiotaGenerateCommandHandler.cs:line 166

This is probably a new error due to changes in the api description since the apigurus version. Do we add a exclusion?


Problem 3:
idempotency (typescript, https://raw.githubusercontent.com/github/rest-api-description/refs/heads...
https://github.com/microsoft/kiota/actions/runs/27618422969/job/81666131202

      error generating the client: Function deserializeIntoWithPath not found in namespace app.client.models
      System.InvalidOperationException: Function deserializeIntoWithPath not found in namespace app.client.models
         at Kiota.Builder.Writers.TypeScript.CodeFunctionWriter.FindFunctionInNameSpace(String functionName, CodeElement codeElement, CodeType returnType) in ... kiota\src\Kiota.Builder\Writers\TypeScript\CodeFunctionWriter.cs:line 447
         at Kiota.Builder.Writers.TypeScript.CodeFunctionWriter.GetDeserializerFunctionName(CodeElement codeElement, CodeType returnType) in ... kiota\src\Kiota.Builder\Writers\TypeScript\CodeFunctionWriter.cs:line 436
         at Kiota.Builder.Writers.TypeScript.CodeFunctionWriter.WriteDiscriminatorInformation(CodeFunction codeElement, CodeParameter parseNodeParameter, LanguageWriter writer) in ... kiota\src\Kiota.Builder\Writers\TypeScript\CodeFunctionWriter.cs:line 398
         at Kiota.Builder.Writers.TypeScript.CodeFunctionWriter.WriteFactoryMethodBody(CodeFunction codeElement, String returnType, CodeFile codeFile, LanguageWriter writer) in ... kiota\src\Kiota.Builder\Writers\TypeScript\CodeFunctionWriter.cs:line 357
         at Kiota.Builder.Writers.TypeScript.CodeFunctionWriter.WriteFactoryMethod(CodeFunction codeElement, CodeFile codeFile, LanguageWriter writer) in ... kiota\src\Kiota.Builder\Writers\TypeScript\CodeFunctionWriter.cs:line 342
         at Kiota.Builder.Writers.TypeScript.CodeFunctionWriter.WriteCodeElement(CodeFunction codeElement, LanguageWriter writer) in ... kiota\src\Kiota.Builder\Writers\TypeScript\CodeFunctionWriter.cs:line 121
         at Kiota.Builder.Writers.LanguageWriter.Write[T](T code) in ... kiota\src\Kiota.Builder\Writers\LanguageWriter.cs:line 149
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCode(LanguageWriter writer, CodeElement element) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 83
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCode(LanguageWriter writer, CodeElement element) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 88
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToSingleFileAsync(LanguageWriter writer, CodeElement codeElement, String outputFile, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 35
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToSingleFileAsync(LanguageWriter writer, CodeElement codeElement, String outputFile, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 37
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToFilePerClassAsync(LanguageWriter writer, CodeNamespace currentNamespace, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 55
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToFilePerClassAsync(LanguageWriter writer, CodeNamespace currentNamespace, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 59
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToFilePerClassAsync(LanguageWriter writer, CodeNamespace currentNamespace, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 59
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToFilePerClassAsync(LanguageWriter writer, CodeNamespace currentNamespace, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 59
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToFilePerClassAsync(LanguageWriter writer, CodeNamespace currentNamespace, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 59
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToFilePerClassAsync(LanguageWriter writer, CodeNamespace currentNamespace, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 59
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToFilePerClassAsync(LanguageWriter writer, CodeNamespace currentNamespace, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 59
         at Kiota.Builder.CodeRenderers.CodeRenderer.RenderCodeNamespaceToFilePerClassAsync(LanguageWriter writer, CodeNamespace currentNamespace, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\CodeRenderers\CodeRenderer.cs:line 59
         at Kiota.Builder.KiotaBuilder.CreateLanguageSourceFilesAsync(GenerationLanguage language, CodeNamespace generatedCode, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\KiotaBuilder.cs:line 668
         at Kiota.Builder.KiotaBuilder.<>c__DisplayClass21_0.<<GenerateClientAsync>b__0>d.MoveNext() in ... kiota\src\Kiota.Builder\KiotaBuilder.cs:line 311
      --- End of stack trace from previous location ---
         at Kiota.Builder.KiotaBuilder.GenerateConsumerAsync(Func`5 innerGenerationSteps, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\KiotaBuilder.cs:line 348
         at Kiota.Builder.KiotaBuilder.GenerateConsumerAsync(Func`5 innerGenerationSteps, CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\KiotaBuilder.cs:line 368
         at Kiota.Builder.KiotaBuilder.GenerateClientAsync(CancellationToken cancellationToken) in ... kiota\src\Kiota.Builder\KiotaBuilder.cs:line 285
         at kiota.Handlers.KiotaGenerateCommandHandler.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken) in ... kiota\src\kiota\Handlers\KiotaGenerateCommandHandler.cs:line 166

Same question as problem 2....

@baywet

Copy link
Copy Markdown
Member

Hi Wolfgang Knauf (@WolfgangHG)
Thank you for the additional information.

Looking at the CI results, it seems the issues are not just limited to TypeScript and Python? Do you have more context here? or is the python class description issue propagated to more languages?

It'd be interesting to share the component definition here, and the references to it to understand how does the generator get into that race condition.

For TypeScript, to me that sounds like a bug in the TypeScript generation, I'd log a detailed bug and suppress for later investigation.

Let me know if you have any additional comments or questions.

@WolfgangHG

Wolfgang Knauf (WolfgangHG) commented Jun 17, 2026 •

Copy link
Copy Markdown
Contributor Author

Added suppression/exclusion for the two failing typescript clients.

Vincent Biret (@baywet) Could you start another CI run? Maybe the python idempotency problem was a random error.

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

The last failing idempotency test was a misconfigured suppression - it must also be excluded with "IdempotencySuppressions" in config.json.

Seems the python idempotency error did not happen again.

I added a small feature for config.json: ExcludePatterns can now be defined for a single language:

  "https://raw.githubusercontent.com/github/rest-api-description/refs/heads/main/descriptions/api.github.com/api.github.com.json": {
    "MockServerITFolder": "gh",
    "Suppressions": [
      {
        "Language": "ruby",
        "Rationale": "https://github.com/microsoft/kiota-abstractions-ruby/issues/73"
      }
    ],
    "ExcludePatterns": [
      {
        "Language": "typescript",
        "Pattern": "/repos/{owner}/{repo}/contents/{path}#GET",
        "Rationale": "Fails for typescript with api version 1.1.4 - https://github.com/microsoft/kiota/issues/7803"
      }
    ]
  },

I created three tickets for the NOTION.COM api and suppressed the failing languages.
The next few days I will continue with filing issues if you consider it reasonable. The tickets might have better subjects (pointing to the OpenAPI feature that causes the error), but I don't have enough knowledge to describe the inner details. If you have the time, could you review them for improvements?

Vincent Biret (@baywet) Could you start another run?

@gavinbarron

Copy link
Copy Markdown
Contributor

Yeah, rerunning that job got it to pass, one thing that might help isolate what's going on with that flaky test is to output the kiota lock files when there is a failure.

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

Gavin Barron (@gavinbarron) I changed the section order in "it/Readme.md" and moved the "Surface area / DOM diff test" part to the end. Hope it is OK for you?

As in the previous test run a bunch of other NOTION.COM idempotency tests failed, I added code to "compare-generation.ps1" (with the help of Copilot) that reports the files that are different. Hope this makes it easier to track down the differences next time.

About your comment

...one thing that might help isolate what's going on with that flaky test is to output the kiota lock files when there is a failure.

Previously, those files were deleted before computing the hash. I changed the code and added them to the exclusion of Get-ChildItem -Exclude @("kiota-lock.json",".kiota.log").

Could you start another test run, just to see whether an idempotency test fails and whether my new code helps analyzing the problem? Maybe I introduced an error when changing the download urls and missed something....

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

The recent changes to "compare-generation.ps1" revealed that "kiota-lock.json" contains the same description hash for both files, though there are differences in the result. So, the same API description was picked for both runs.
The file ".kiota.log" is still missing from the uploaded artifact. "Compress-Archive" skips hidden files (starting with a dot) on linux. I could rename the file to "kiota.log" to make it part of the upload.

But I think I found the reason for the idempotency errors and created #7927 - could we continue discussion there?

@baywet

Copy link
Copy Markdown
Member

For the logs, instead of uploading them in the zip, which is going to make them difficult to access, we should instead merge them into the action logs with something like this

- name: Run tool and merge logs on failure
  if: always()
  run: |
    if [ -f my-file.log ]; then
      echo "::group::Tool Logs (Post-Execution)"
      cat my-file.log
      echo "::endgroup::"
    fi

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

Vincent Biret (@baywet) I tried to implement your suggestion, but each of the two ".kiota.log" is placed inside a directory with a random GUID name (see content inside "idempotency-...zip"). "compare-generation.ps1" would have to return the two folder names to the CI workflow.
So I followed the "rename to kiota.log" idea and hope it is OK for you.

Most of kiota logging is written to the console, only INFO and DEBUG output (like "KiotaBuilder loaded description from local source" - the relevant part for me that confirmed that the api file was really picked from a local source) is missing here. And this now can be found in the artifact zip. But most of the time, this output will not be relevant.

If you prefer writing the log to the CI output, please guide me on how to achieve this.

Otherwise, could you start another CI run? It would be ironic if the idempotency issue does not happen now, where I want to test the modified diagnostic code 😄.

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

OK, I forgot to add the log for the second test. But the log is not helpful anyway - it just contains warning messages, but no INFO/DEBUG log. So it is identical to the console output github action. Strange - when running it locally, it printed INFO/DEBUG. Is this something special of github CI?
I tend to reverting the latest change again as it brings no benefit. Vincent Biret (@baywet) What do you think?

@baywet

Copy link
Copy Markdown
Member

Wolfgang Knauf (@WolfgangHG) can't we simply pass --ll debug to kiota where we invoke it instead?

@WolfgangHG

Copy link
Copy Markdown
Contributor Author

Vincent Biret (@baywet) I added the switch - thanks for the suggestion. Let's see the effect in CI. Hopefully, the action output now contains the debug logging and the upload of log files is not necessary.

@WolfgangHG

Wolfgang Knauf (WolfgangHG) commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks! Kiota debug messages are now added to the action log. So no need to add ".kiota.log" to the result zip. I reverted this change.

Now we have to sort out the idempotency issue #7927.

@gavinbarron
Gavin Barron (gavinbarron) enabled auto-merge (squash) July 20, 2026 21:49
@gavinbarron
Gavin Barron (gavinbarron) merged commit 0361427 into microsoft:main Jul 20, 2026
312 checks passed
@WolfgangHG

Copy link
Copy Markdown
Contributor Author

Gavin Barron (@gavinbarron) Thanks for merging and many thanks for looking into and fixing the idempotency issue!

@WolfgangHG
Wolfgang Knauf (WolfgangHG) deleted the apigurus branch July 21, 2026 19:23
Eelco Los (EelcoLos) added a commit to EelcoLos/kiota that referenced this pull request Aug 12, 2026
googlemaps/openapi-specification dropped the dist/ folder from main,
causing 404s on download-openapi-specs. Same fix main applied in
0361427 (microsoft#7774): pin to refs/tags/v1.22.5 where dist/ still exists.
Eelco Los (EelcoLos) added a commit to EelcoLos/kiota that referenced this pull request Aug 12, 2026
apisguru::github.com:api.github.com routes through the APIs.guru proxy,
same class of flakiness main moved off in 0361427 (microsoft#7774). Swapped to
the direct rest-api-description URL main uses. Also fixes it/config.json:
its suppression/mock-folder lookup is keyed by the exact matrix string,
so the googlemaps tag-pin from the prior commit and this api.github.com
swap both needed their config.json keys updated to match or the
suppressions would silently stop applying.

Verified download-openapi-specs.ps1 against the new URL locally.
Eelco Los (EelcoLos) added a commit to EelcoLos/kiota that referenced this pull request Aug 12, 2026
The github/rest-api-description spec's /repos/{owner}/{repo}/contents/{path}
GET response is a union type that generates a "WithPath" model class
main's generator doesn't correctly emit (missing symbol in java,
missing file in dart, missing deserializer registration in typescript).
This is an open, unfixed kiota generator bug (main doesn't generate
correct code for it either) that main works around by suppressing
dart/typescript entirely for this spec (microsoft#7821, microsoft#7862) and excluding
just that one endpoint for java (microsoft#7829), rather than a real fix to
backport.

Added the matching per-language Suppressions/ExcludePatterns entries
to it/config.json, and backported the "Language" field filtering for
ExcludePatterns from main's 0361427 (microsoft#7774) to
get-additional-arguments.ps1 -- our version applied every
ExcludePattern to every language regardless of a Language field,
so the java-only exclude would otherwise have leaked to every
language's generation command.

Verified locally: get-additional-arguments.ps1 emits the contents/path
exclude only for java, not csharp; get-is-suppressed.ps1 suppresses
dart/typescript but not java/csharp/python for this description.
Vincent Biret (baywet) added a commit that referenced this pull request Aug 13, 2026
* fix: do not use the install command from the OpenAPI extension (#7883)

Signed-off-by: Vincent Biret <vibiret@microsoft.com>
Co-authored-by: Vincent Biret <vibiret@microsoft.com>

* fix: reject unsafe static_template.file references in plugin manifest generation (backport of #7892 / GHSA-4jwf-m4wg-8p66)

Hand-ported against the pre-3.x extension shape (JsonObject/plain string)
since upstream's fix depends on the typed ExtensionResponseSemanticsStaticTemplate
model and an unrelated LoggerMessage refactor that don't exist on this line.

* chore: bump Microsoft.OpenApi/YamlReader 2.0.0 -> 2.7.6 (GHSA-v5pm-xwqc-g5wc)

Same-major patch bump, no Microsoft.AspNetCore.OpenApi conflict.
Bisected an apparent DivergentResponseSchemaTests failure at this version to a
pre-existing race on DivergentResponseSchema's shared static validStatusCodes
HashSet under xUnit's parallel test execution, unrelated to this bump.

* ci: adapt release pipeline to the v1.29.x source tree

Pulls in main's current ci-build.yml (private feed routing, release
idempotency guards) but corrects the three references that assume a
newer source layout than what security/1-29-x actually has:

- kiota.slnx -> kiota.sln (this branch predates the .sln to .slnx move)
- publish TFM net10.0 -> net9.0 (kiota.csproj here targets net8.0/net9.0 only)
- vscode/packages/npm-package/lib/runtime.json -> npm-package/runtime.json
  (the lib/ subfolder doesn't exist on this branch)

No other changes.

* chore: bump OpenTelemetry packages 1.13.1 -> 1.15.3 (GHSA-4625-4j76-fww9, GHSA-mr8r-92fq-pj8p, GHSA-q834-8qmm-v933)

OpenTelemetry.Exporter.OpenTelemetryProtocol 1.13.1 has three known
moderate-severity advisories (local blob injection via disk-retry temp
path, unbounded grpc-status-details-bin parsing, unbounded OTLP HTTP
response body reads). 1.15.3 is the first version patching all three.

Bumps OpenTelemetry and OpenTelemetry.Extensions.Hosting to the same
1.15.3 to keep the OpenTelemetry core packages version-aligned, same
pattern as the existing Microsoft.OpenApi same-major bump on this
branch. Instrumentation.Http/Runtime are versioned independently
upstream and unaffected by these advisories, left as-is.

* fix: remove leftover git conflict markers from CHANGELOG.md

Unresolved conflict markers from an earlier cherry-pick were
accidentally committed. No content change beyond removing the markers
and one stray blank line.

* fix: escape literal injection across all language writers (backport of #7603 / GHSA-2hx3-vp6r-mg3f / CVE-2026-41134)

Attacker-controlled OpenAPI description content (defaults, enum
values, wire names, discriminator mappings, doc comments, deprecation
info) emitted as string literals into generated client code could
break out of the literal and inject arbitrary code in the generated
client's language, across every writer (C#, Dart, Go, HTTP, Java, PHP,
Python, Ruby, TypeScript).

Adds/uses per-language literal sanitizers at all emission sites.

Hand-resolved conflicts against upstream's fix (Go/Java/Python getter
bodies, TypeScript composed-type deserializer) were pure indentation
drift and one unrelated call to SortTypesByInheritance (a feature not
present on this branch); kept this branch's existing formatting/logic
and applied only the sanitizer calls. Dropped one unrelated test
(GetFactoryMethodName_ReturnsCamelCase_WhenTypeIsAliasedButMethodIsNot)
that depends on aliased-type factory-method resolution not present on
this branch.

* fix(writers/python): prevent code injection via x-ms-enum description newlines (backport of #7735 / GHSA-7f3j-j7jj-r3vr / CVE-2026-59862)

PythonConventionService.RemoveInvalidDescriptionCharacters did not
strip newline characters. A malicious OpenAPI spec could inject
arbitrary Python code via x-ms-enum description fields by embedding
newlines that break out of inline comments (# ...) or docstrings.

Dropped an unrelated dependency bump (StreamJsonRpc/Nerdbank.MessagePack/
System.CommandLine) that rode along in the upstream commit's "Secondary"
changes, out of scope for this branch. Also dropped
.github/instructions/writer-literal-security.instructions.md since it
modifies a Copilot review-instructions file this branch doesn't have
(added by an unrelated, un-backported commit, #7621).

* fix(ruby): escape interpolation markers in generated string literals (backport of #7746 / GHSA-xg2h-5xr2-29jw / CVE-2026-59861)

Prevent Ruby code injection in generated clients by escaping # in
schema-derived values emitted into Ruby double-quoted literals.

Dropped upstream's enum/datetime/date/time/guid-specific default-value
formatting for backing-store/additional-data properties, an unrelated
feature this branch doesn't have; kept the existing plain default-value
assignment shape and applied only the Ruby sanitizer swap.

* fix(csharp): strip newlines from doc comment text to prevent code injection (backport of #7831 / GHSA-3hrf-2gc2-mx32 / CVE-2026-59860)

Newlines in an OpenAPI externalDocs.description (or other doc-comment
sources) could break out of the C# /// doc comment and inject
arbitrary code. Strips \r, \n, NEL, LS, PS from doc-comment text and
replaces tabs with spaces before emission.

* fix(php): escape $ in double-quoted string literals to prevent code injection (backport of #7863 / GHSA-jqwh-526h-c92j / CVE-2026-59859)

PHP interpolates $var, ${...} and {$...} inside double-quoted strings.
The shared SanitizeDoubleQuote helper does not escape $, so
attacker-controlled OpenAPI input (descriptions, enum values, content
types, discriminator/query names) emitted into PHP double-quoted
literals could inject and execute arbitrary PHP/OS commands when the
generated client runs.

Adds SanitizePhpDoubleQuoteLiteral on PhpConventionService, mirroring
the existing SanitizeDartDoubleQuoteLiteral, used at all PHP
double-quote emission sites.

* fix: sanitizes the client class and namespace names to avoid code injection (backport of #7884 / GHSA-4vv7-jj25-4gh6 / CVE-2026-59866)

ClientClassName and ClientNamespaceName loaded from the x-ms-kiota-info
OpenAPI extension (or settings) were used unsanitized in generated
code and file paths, allowing an attacker-controlled OpenAPI
description to inject arbitrary paths or code via those values.

Test-file TestContext.Current.CancellationToken usages (xunit v3 API,
unavailable on this branch's xunit 2.9.3) replaced with this branch's
existing convention (new CancellationToken() / omitted).

* fix: validate workspace output paths are sub-directories (backport of #7885 / GHSA-4rj6-vrwv-wr8m / CVE-2026-59863)

A workspace configuration file (kiota-config.json) committed to a repo
could set a client or plugin's outputPath to an absolute path or a
path escaping the workspace directory. Running kiota against that
workspace would then write generated files outside the intended
project tree.

Validates every client/plugin outputPath against the workspace root
when loading the workspace configuration, rejecting rooted or
escaping paths.

* chore: reorganize CHANGELOG.md for the 1.29.x line

Removed the [1.30.0] through [1.32.3] version headings: they describe
main's release history, not this branch's, and their content either
doesn't apply here (unrelated bug fixes never backported to this
line) or duplicates entries already listed under [Unreleased] for the
CVE fixes actually ported here. This branch will release as a 1.29.x
patch, so nothing newer than [1.29.0] should appear as if released on
this line.

* style: apply dotnet format across the repo

Brings the tree in line with the current formatting ruleset, mostly
missing blank lines after namespace declarations and using blocks.
No behavioral changes. Fixes the "Check formatting" CI gate, which
was failing repo-wide on this branch's baseline (v1.29.0 predates
the current formatter/ruleset) independent of the security fixes.

* feat: add an allow list parameter for external references resolution (backport of #7888 / GHSA-rg4h-fpcp-2qm8 / CVE-2026-59867)

External $ref resolution during OpenAPI parsing was previously
unrestricted, allowing a malicious or compromised OpenAPI description
to trigger SSRF or local/remote file inclusion via $ref targets kiota
would follow and load. Adds AllowedExternalOriginsStreamLoader and a
new --allowed-external-origins CLI parameter (default: deny all
external refs) to restrict resolution to an explicit allow list
('*', full URIs, URI patterns, full/relative paths, path patterns).

Hand-ported the CLI wiring (13 command/handler files) against this
branch's System.CommandLine 2.0.0-beta4 API (InvocationContext /
GetValueForOption), since upstream's commit rides on main's later
System.CommandLine 2.0.8 API (ParseResult / GetValue) migration, which
this branch doesn't have. GetAllowedExternalOriginsOption similarly
rewritten against the old Option<T> constructor API (no
DefaultValueFactory/HelpName init-only properties on this version).
Core library changes (AllowedExternalOriginsStreamLoader,
OpenApiDocumentDownloadService) applied with no changes needed.

Known gap: one test, AllowedExternalOriginsLoadMatchingReferences,
fails locally with a "circular reference detected" error from
Microsoft.OpenApi's schema resolver. This appears to be a behavior
difference between Microsoft.OpenApi 2.7.6 (this branch, same-major
bump from 2.0.0) and whatever 3.x version upstream's test was written
against, triggered by the test's mock HTTP response reusing the same
component name ("Pet") as the referencing document. The
AllowedExternalOriginsStreamLoader class itself (the actual
security-relevant code) and its 8 other dedicated tests all pass;
this looks like a test-fixture/library-version interaction, not a
flaw in the allow-list logic. Flagging rather than silently fixing
the fixture, since I'm not confident yet whether adjusting the mock
masks a real resolution-order issue or not.

Unpushed: prepared in case this fix is approved, per discussion on
the PR. Not yet pushed to keep the reviewed 7-commit set untouched
pending review.

* Fix redundant pattern-matching precedence flagged by CS9336

`is not A or B` parses as `(is not A) or B`, not the intended
`is not (A or B)`. Parenthesize per baywet's review comment on #8038.

* ci: fix stale msgraph-sdk-powershell dev-branch URL to main

The dev branch no longer exists; Mail.yml (and the other openApiDocs
fixtures referenced in launch.json) moved to main, causing 404s in
test_and_generate_binaries. Same fix upstream applied in beb99d9 (#7364).

* ci: pin googlemaps openapi spec to tag, dist/ removed from main

googlemaps/openapi-specification dropped the dist/ folder from main,
causing 404s on download-openapi-specs. Same fix main applied in
0361427 (#7774): pin to refs/tags/v1.22.5 where dist/ still exists.

* ci: replace apisguru proxy for api.github.com, sync config.json keys

apisguru::github.com:api.github.com routes through the APIs.guru proxy,
same class of flakiness main moved off in 0361427 (#7774). Swapped to
the direct rest-api-description URL main uses. Also fixes it/config.json:
its suppression/mock-folder lookup is keyed by the exact matrix string,
so the googlemaps tag-pin from the prior commit and this api.github.com
swap both needed their config.json keys updated to match or the
suppressions would silently stop applying.

Verified download-openapi-specs.ps1 against the new URL locally.

* fix: escape backslashes in C# property default value string literals

WriteConstructorBody hand-rolled quote/newline escaping for string
default values, missing backslashes. A default like "\z|[^0-9A-Za-z]"
(regex pattern, e.g. GitHub's rest-api-description secret-scanning
custom pattern schema) round-tripped its raw backslashes straight into
the generated literal, producing invalid C# (CS1009: Unrecognized
escape sequence). Switched to SanitizeQuotedStringLiteral(), the same
literal-escaping helper already used elsewhere in this file and added
across writers by 6dbee0f's literal-injection CVE fix, which already
escapes backslashes correctly. Same fix main applied in ee39d2a
(#7414), scoped down to just the string-escaping change since that
commit's DateTime/numeric/boolean default-value handling is an
unrelated feature, not a bug on this branch's own baseline.

Reproduced and verified locally: generated + compiled the C# client
for GitHub's rest-api-description spec (the spec that surfaced this),
0 errors after the fix vs 2x CS1009 before.

* ci: match main's IT suppressions for dart/typescript/java WithPath bug

The github/rest-api-description spec's /repos/{owner}/{repo}/contents/{path}
GET response is a union type that generates a "WithPath" model class
main's generator doesn't correctly emit (missing symbol in java,
missing file in dart, missing deserializer registration in typescript).
This is an open, unfixed kiota generator bug (main doesn't generate
correct code for it either) that main works around by suppressing
dart/typescript entirely for this spec (#7821, #7862) and excluding
just that one endpoint for java (#7829), rather than a real fix to
backport.

Added the matching per-language Suppressions/ExcludePatterns entries
to it/config.json, and backported the "Language" field filtering for
ExcludePatterns from main's 0361427 (#7774) to
get-additional-arguments.ps1 -- our version applied every
ExcludePattern to every language regardless of a Language field,
so the java-only exclude would otherwise have leaked to every
language's generation command.

Verified locally: get-additional-arguments.ps1 emits the contents/path
exclude only for java, not csharp; get-is-suppressed.ps1 suppresses
dart/typescript but not java/csharp/python for this description.

* fix(python): rename types that collide once snake cased

Python modules are named after the snake cased type name, so the inline
schema class CodeScanningVariantAnalysis_status and the component schema
class CodeScanningVariantAnalysisStatus both resolve to the same file,
code_scanning_variant_analysis_status.py. One silently overwrote the
other and the losing type's importers kept referencing a symbol that no
longer existed, which is the mypy "has no attribute ... [attr-defined]"
failure on the python integration test. Which of the two wins is
nondeterministic, which is why CI reported the error in both directions
(CodeScanningVariantAnalysis_status missing in one module,
RepositoryRulesetConditions missing in the other).

Adds a DisambiguateSnakeCasedNames pass to PythonRefiner, run right
after CorrectCommonNames so it lands before imports are materialized.
Sibling classes/enums are grouped by snake cased name and later
collisions get a trailing underscore, ordered with StringComparer.Ordinal
for determinism. Renaming the type is sufficient because CodeType.Name is
computed from TypeDefinition.Name, so the file name, import path, import
symbol and every type reference follow automatically; no writer changes.

No upstream fix to backport: main has the same latent bug, its
PythonRefiner and PythonPathSegmenter differ from this branch only by the
unrelated ShortenOversizedNamespaceSegments work.

Verified against the github/rest-api-description description used by the
integration test. An AST scan resolving every relative import against the
symbols actually present in the target module goes from 3 broken pairs to
0 of 13302. Both previously lost types are emitted again. The added test
fails without the fix (Model_status vs Model_status_).

Ruby and Dart segment file names the same way and so share this latent
bug; left alone here to keep the change scoped to the reported failure.

* fix: guard against circular discriminator resolution

A discriminator mapping can point at a composed (oneOf/anyOf) schema
whose own discriminator maps back to an ancestor, so GetDiscriminatorMappings
calls GetCodeTypeForMapping calls CreateModelDeclarations calls
CreateComposedModelDeclaration calls GetDiscriminatorMappings with nothing
to break the loop. There is no cycle detection anywhere on that path.

Tracks the component schemas currently being resolved as discriminator
targets, pushed before recursing and popped in a finally, so only genuine
ancestor cycles are cut while the same component referenced from sibling
branches still resolves. Returning null is the already established
"skip this mapping" path, GetDiscriminatorMappings filters nulls out.

Prerequisite for moving the Microsoft.OpenApi pin to 2.12.0: the schema
shapes 2.12.0 produces close this loop and overflow the stack, aborting
the whole test run. Bisected to confirm, 2.7.6, 2.10.0 and 2.11.0 are all
fine and 2.12.0 is where it starts. main's ThreadLocal modelCreationDepth
guard does not cover this, it wraps CreatePropertiesForModelClass and this
cycle never passes through that method.

Behaviour preserving on the current pin: generating the C# client for
github/rest-api-description before and after gives byte identical output
across all 3704 files including the log, even though the guard trips 108
times on that description. Logged at debug rather than warning for that
reason, tripping here is normal rather than anomalous.

* fix: bump Microsoft.OpenApi to 2.11.0 so external ref allow list works

AllowedExternalOriginsLoadMatchingReferences failed on 2.7.6 with
"Circular reference detected while resolving schema" thrown from
OpenApiWorkspace.ResolveSubSchema while RegisterComponents resolved
the root document's component-level external $ref. The deny path of
the CVE-2026-59867 allow list was fine, but the allow path could not
actually load a permitted external reference on the version 1.29.0
shipped.

2.11.0 fixes that resolution bug and is the last 2.x before the
breaking changes: 2.12.0 folds anyOf: [string, integer] into a single
flags-enum Type and obsoletes IOpenApiSchema.Example, which is the
upgrade work that belongs on main rather than on a security branch.

Full suite on 2.11.0: 1967 passed, 0 failed, 2 skipped (was 1 failure
on 2.7.6). The anyOf tests pass unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUifZksSV3pi2zWxvs29ka

* ci: exclude the WithPath endpoint for typescript too

Main excludes /repos/{owner}/{repo}/contents/{path}#GET for both java
and typescript; the previous backport only carried the java entry, so
typescript idempotency against the github description still crashed
generation with "Function deserializeIntoWithPath not found in
namespace ApiSdk.models". The integration suppression did not cover it
because idempotency generates the client before any comparison.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUifZksSV3pi2zWxvs29ka

* ci: follow the github spec rename of byOrgId to byOwnerId

The github/rest-api-description spec is tracked from its main branch,
and the /repos/{owner}/{repo} path parameter is now owner rather than
org, so the generated ReposRequestBuilder exposes byOwnerId. Matches
the same change on kiota main.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUifZksSV3pi2zWxvs29ka

* fix: move to Microsoft.OpenApi 2.12.0 and narrow folded union types

2.12.0 is the floor for the remaining security fixes, so 2.11.0 is not
an option after all. Two things change on 2.12.0.

IOpenApiSchema.Example becomes obsolete in favour of Examples, so the
schema copy in PluginsGenerationService copies Examples now.

The reader also folds a union of primitive types, anyOf: [string,
integer], into a single Type carrying both flags and clears AnyOf.
SelectFirstAnyOneOfVisitor therefore never sees a union, and the
generated plugin description kept "Integer | String" where it used to
narrow to "String". NarrowMultipleTypes restores a single type.

Worth flagging: JsonSchemaType is a flags enum, so the order the types
were authored in is gone by the time we see it, and "take the first
entry" cannot be honoured literally any more. The rule is String when
present, since every JSON scalar round trips through it, otherwise the
lowest flag so the result stays deterministic. For anyOf: [string,
integer] that reproduces the previous output exactly.

Full suite on 2.12.0: 1967 passed, 0 failed, 2 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUifZksSV3pi2zWxvs29ka

* docs: changelog for the OpenApi 2.12.0 bump and union narrowing

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUifZksSV3pi2zWxvs29ka

* docs: reference the advisories and cover the missing security fixes

The changelog described the fixes but never named them, so nobody
reading it could line an entry up with an advisory. Each security entry
now carries its GHSA link and CVE.

Two fixes on this branch had no entry at all:

- the static_template.file path escape rejection (#7892 /
  GHSA-4jwf-m4wg-8p66)
- the OpenTelemetry 1.13.1 to 1.15.3 bump (GHSA-4625-4j76-fww9,
  GHSA-mr8r-92fq-pj8p, GHSA-q834-8qmm-v933)

Also folded GHSA-v5pm-xwqc-g5wc into the Microsoft.OpenApi entry, since
that bump started as a fix for it and has since moved on to 2.12.0.

All of these advisories were published in July 2026 or earlier, so
naming them here discloses nothing new.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUifZksSV3pi2zWxvs29ka

* fix: prefer the numeric type when a numeric union carries a format

Per review feedback: int | string is what System.Text.Json's
JsonNumberHandling.AllowReadingFromString advertises, the ASP.NET Core
default, so the pair should resolve to the numeric type rather than
collapsing to a string. The format is correlated first, and a string
only wins when there is no numeric format to go on.

This matches the rule GetPrimitiveType already applies for clients on
main, backported here for the plugin path.

Suite: 1967 passed, 0 failed, 2 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUifZksSV3pi2zWxvs29ka

* chore: prepare the 1.29.1 patch release

Ran scripts/bump-version.ps1 -kind patch and scripts/prepare-release.ps1
as requested, which moves the unreleased security entries under 1.29.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUifZksSV3pi2zWxvs29ka

---------

Signed-off-by: Vincent Biret <vibiret@microsoft.com>
Co-authored-by: Gavin Barron <gavinbarron@microsoft.com>
Co-authored-by: Vincent Biret <vibiret@microsoft.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants