Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
160827 stories
·
33 followers

Wide Events vs. Three Pillars: AI Observability Costs

1 Share
AI agents make telemetry costs harder to predict. This post compares the three pillars against the wide event model, and explains why wide events keep AI observability costs predictable without sacrificing the context engineers need.
Read the whole story
alvinashcraft
47 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Kubernetes access via an identity provider: Public client, not confidential

1 Share

Access control belongs on the same day-zero checklist as networking and storage.

On most on-prem clusters, it never makes the list.

The Identity Gap

Managed cloud Kubernetes ships IAM or SSO integration out of the box. Self-hosted clusters don’t. Access defaults to a static client certificate or a long-lived token, issued once and rarely revisited. That certificate keeps working long after the person it was issued to has left, changed roles, or lost the device it lives on. Nothing in the cluster’s authentication path checks whether they should still have access. Revoking it means finding every copy of a file, and in practice, that doesn’t happen completely. The moment more than one or two people need different levels of access, managing that per person, per file, becomes its own ongoing job.

Put an identity provider (Keycloak or any OIDC-compliant provider) in front of the cluster instead. Access should follow an account and its group membership, not a certificate file. Configure it with a public OIDC client using PKCE, not a confidential client with a secret. Access changes become identity operations: add someone to a group, remove someone from a group. No file distribution required.

Architecture: three moving parts

The integration has three components that need to agree with each other:

  • kubectl, with the kubelogin exec plugin. Starts the login, gets a token from the identity provider, and attaches it to every API request.
  • The identity provider (Keycloak). Authenticates the user and issues an ID token carrying their username and group membership.
  • kube-apiserver, configured with --oidc-issuer-url, --oidc-client-id, and --oidc-groups-claim. Validates the token, extracts username and groups, and lets RBAC decide what that identity can do.
Figure 1: kubectl authenticates against the identity provider, then presents the resulting token to kube-apiserver, which validates it and hands it off to RBAC.

kubectl authenticates against the identity provider, then presents the resulting token to kube-apiserver, which validates it and hands it off to RBAC.

kubectl never talks to the API server first. A kubectl exec-credential plugin (kubelogin, also distributed as “kubectl oidc-login”) intercepts the request, drives the browser-based login against the IdP, and hands the resulting ID token back to kubectl as a bearer credential. The API server validates that token directly against the IdP’s public signing keys. It never needs network access to the IdP itself beyond fetching those keys once.

The client configuration decision that matters

Configure this client as public, not confidential. A confidential client issues a client secret, which then gets pasted into the kubelogin plugin config, and ships to every machine that needs cluster access.

A secret that has to be distributed to every client that uses it isn’t functioning as a secret. It’s a shared static credential with extra steps, and rotating it means a coordinated config push to every machine rather than disabling one compromised identity.

OAuth 2.1 already settles this for native and command-line applications. Make the client public. Issue no secret at all. Use PKCE (Proof Key for Code Exchange) instead, which stops anyone who intercepts the authorization code from redeeming it. PKCE works by having the client generate a random value locally, send a hash of it with the initial login request, then prove possession of the original value when exchanging the code for a token. An interceptor holding only the code can’t complete that proof.

The client, in Keycloak’s admin console, ends up configured as:

  • Client ID: kubernetes
  • Client authentication: Off (public client, no secret issued)
  • Standard flow: On
  • Direct access grants: Off
  • Require PKCE: On, method S256
  • Valid redirect URIs: http://127.0.0.1:* and http://localhost:* (loopback only, nothing external)
  • Web origins: http://127.0.0.1:* and http://localhost:*
  • Client scopes: openid, profile, email, groups
Figure 2: General settings: the Kubernetes client, registered as OpenID Connect

General settings: the Kubernetes client, registered as OpenID Connect

Figure 3: Access settings: redirect URIs and web origins locked to loopback only

Access settings: redirect URIs and web origins locked to loopback only

Figure 4: Capability config: Client authentication Off, Standard flow, Require PKCE On (S256)

Capability config: Client authentication Off, Standard flow, Require PKCE On (S256)

Deployment walkthrough

1. Add the groups claim mapper

Kubernetes has no concept of “users” as a first-class object. RBAC binds to usernames and groups asserted by the token, so the IdP needs to actually put group membership into the ID token. “In Keycloak”is a protocol mapper on the client scope, of type Group Membership, mapped to the claim name groups.

Figure 5: Group Membership mapper on the realm-level 'groups' client scope: Token Claim Name 'groups', Add to ID token On

Group Membership mapper on the realm-level ‘groups’ client scope: Token Claim Name ‘groups’, Add to ID token On

2. Point kube-apiserver at the issuer

--oidc-issuer-url=https://<your-keycloak-host>/realms/<realm>
 --oidc-client-id=kubernetes
 --oidc-username-claim=preferred_username
 --oidc-groups-claim=groups

If Keycloak’s certificate isn’t signed by a publicly trusted CA (the common case for a self-hosted) on-prem identity provider, add one more flag pointing at that CA’s certificate:

--oidc-ca-file=/etc/kubernetes/pki/oidc-ca.crt

The API server needs to trust this connection to fetch the issuer’s signing keys. Without it, OIDC authentication fails with a TLS verification error that has nothing to do with the login flow itself, which makes it a confusing one to debug the first time you hit it.

3. Configure the kubectl side

kubeconfig gets an exec-credential entry instead of embedded certs or a static token:

users:
 - name: oidc
   user:
 	exec:
   	apiVersion: client.authentication.k8s.io/v1
   	command: kubectl
   	args:
     	- oidc-login
     	- get-token
     	- --oidc-issuer-url=https://<your-keycloak-host>/realms/<realm>
     	- --oidc-client-id=kubernetes

No secret field. There’s nothing to put there.

4. Bind groups to RBAC

apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
   name: platform-viewers
 subjects:
   - kind: Group
 	name: platform-viewer
 	apiGroup: rbac.authorization.k8s.io
 roleRef:
   kind: ClusterRole
   name: view
   apiGroup: rbac.authorization.k8s.io

Access changes now happen entirely in the IdP. Add someone to the platform-viewer group, and the next token they mint carries that group. The binding above applies immediately. No cluster-side change. No new kubeconfig to distribute.

Try it out

Using kubelogin as the exec plugin, a first login looks like this from the terminal:

$ kubectl get pods
 Opening in existing browser session.
 NAME                    	READY   STATUS    RESTARTS   AGE
 web-7f9c9c4d8-2xk9p     	1/1 	Running   0      	3d

The first call opens a browser window against the IdP; every call after that reuses the cached token until it expires, at which point kubelogin silently uses the refresh token to get a new one without another browser round-trip.

To confirm what identity and groups actually landed in the token:

$ kubectl auth whoami
ATTRIBUTE   VALUE
 Username	jane.doe@example.com
 Groups  	[platform-viewer system:authenticated]

The bottom line

None of this requires reworking how the cluster runs. It is a public OIDC client, one group membership mapper, a handful of RBAC bindings, and a kubectl plugin many engineers already have installed for other clusters. The setup cost is a single afternoon, not a platform migration.

What changes is what the cluster gets in return. Access follows group membership in the identity provider instead of a certificate file, so granting or revoking a level of access becomes a group change, not a search for every copy of a file across every laptop. There is a deeper benefit too. Kubernetes can log every request that hits its API server, but that audit trail is only as useful as the identity attached to each entry. A shared kubeconfig authenticating everyone as the same generic identity, often literally ‘cluster-admin’ means every audit log entry says the same thing no matter who actually ran the command. Federate identity through an OIDC provider instead, and every request the API server logs carries the person who actually made it. The audit trail stops being a list of anonymous actions and becomes an actual record of who did what, and it costs far less to set up than most teams assume.

Read the whole story
alvinashcraft
47 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

TypeScript 7 in WebStorm: Faster Coding Assistance for Angular and React, No Migration Required

1 Share

TypeScript 7 is a real game-changer, and its new Go-based language engine fundamentally alters how IDEs integrate with TypeScript. And what’s more, WebStorm 2026.2 ships stable support for it, including for Angular and React projects.

No migration is required – if your team is locked on an older TypeScript version for infrastructure reasons, your project constraints stay exactly where they are. What changes is the speed and quality of coding assistance you get in WebStorm.

This post walks through what TypeScript 7 support means in practice for Angular and React users.

Under the hood: Why the Go-based engine changes things

TypeScript 7 replaces the Node.js-based language service with a new engine written in Go. The result is a faster compiler that does less work to deliver the same or better coding assistance.

For WebStorm, this meant rethinking how the IDE integrates with TypeScript at the language-service level. Rather than relying on the existing plugin layer, we built native support for the Go-based engine, so it can power coding assistance directly. The difference is most apparent in larger codebases, where the old engine’s overhead was most visible.

Angular: Full TypeScript 7 support before anyone else

TypeScript 7 support for Angular projects is fully stable in WebStorm 2026.2.2. You can switch to the Go-based engine in WebStorm in your preferences with no changes to your project required.

According to official Microsoft publications, the new compiler is up to 10x faster than its Node.js-based predecessor. We ran TypeScript 7 on the Kibana codebase and saw project load times drop from around 12 seconds to 3 seconds. Kibana is one of the largest open-source TypeScript codebases out there, so that’s a meaningful result and a good proxy for what large Angular monorepos can expect.

You can choose TypeScript 7.0 for coding assistance in the WebStorm preferences for your Angular project to benefit from the improved performance.

You may wonder how that is possible when neither the Angular compiler nor VS Code’s coding assistance supports TypeScript 7.0. WebStorm ships with its own Angular template transpiler ported from the Angular compiler to Kotlin, which gives us a lot of flexibility. For Node.js-based TypeScript, we have developed a Volar plugin to support source mapping in the TypeScript compiler. For Go-based TypeScript, we have implemented a similar solution by porting parts of Volar to Koltin and adapting it to our infrastructure.

The general idea is that there is a layer that collects transpiled code and mappings, and translates IDE requests from coordinates in the original source code to the generated code. The TypeScript compiler, on the other hand, sees only the generated code and receives requests with translated coordinates. This solution allows us to transpile TypeScript files and provide code assistance in inline Angular templates. The TypeScript-Go content-mappers feature is currently limited to non-TypeScript files, and it appears it will not support Angular use cases.

We’re looking forward to seeing how the Angular compiler will be redesigned for TypeScript 7.0. But even now, you can already enjoy better performance in your Angular projects with WebStorm!

React and Vue updates

Already using TypeScript 7 in your React project? WebStorm has you covered. The Go-based engine powers coding assistance out of the box. Update WebStorm, select TypeScript 7 in your preferences, and you’re good to go.

We are also working on porting the Vue transpiler to Kotlin and Kolar (coming soon), and we are actively working to find the best solution to support Vue with TypeScript 7. All we need to do is evaluate whether it will be done through the official content-mappers solution or using our Kotlin transpiler and Kolar.

What’s next

For React, TypeScript 7 support is stable and ready to use today. For Angular, we’re continuing to refine the integration and watching how the Angular compiler evolves to natively support TypeScript 7. If you run into anything unexpected in your projects, we’d love to hear from you. Feedback from real codebases shapes what comes next!

Download WebStorm 2026.2.2

Read the whole story
alvinashcraft
48 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Bring your own model to GitLab Duo Self-Hosted with Microsoft Foundry

1 Share

For many organizations, the question about AI coding tools isn't whether they help, but where the code goes. Teams under data sovereignty, residency, or regulatory constraints need to know which network handles their source code before they can adopt anything. GitLab Duo Self-Hosted answers that by letting administrators connect GitLab Duo features to models running on infrastructure they choose, with control over hosting, region, network path, and credentials.

In this tutorial, we'll connect GitLab Duo Self-Hosted to models hosted in Microsoft Foundry. Foundry is worth treating as a general-purpose serving platform rather than an OpenAI endpoint: Its catalog spans OpenAI GPT, Anthropic Claude, Meta Llama, and Mistral, and the families GitLab supports overlap heavily with what Foundry offers.

That matters because GitLab lets you assign a model per feature. You can run one family for agentic work, a code-specialized model for Code Suggestions, and a smaller model where request volume dominates, all deployed and billed through one Azure subscription.

The setup steps are the same regardless of family. Only the model you deploy, the deployment name you reference, and the Model family you select in GitLab change.

Microsoft's catalog moves quickly and will contain releases newer than GitLab's supported-model matrix. Catalog availability alone does not establish GitLab Duo support, so always check both vendors' documentation before choosing a model.

Why GitLab Duo Self-Hosted?

GitLab Duo Self-Hosted lets you connect GitLab Duo to models deployed on-premises or through a supported cloud provider. Microsoft Foundry is useful when your organization already operates in Azure and wants to manage model deployments, access, networking, and consumption there.

Key benefits include:

  • Deployment choice: Select the Azure region and deployment type that meet your availability and data-residency requirements.
  • Multiple model families, one platform: Deploy GPT, Claude, Llama, or Mistral models side by side instead of contracting with each provider separately.
  • Feature-level configuration: Assign models to individual GitLab Duo features instead of applying one model globally, mixing families if that suits your workloads.
  • Azure integration: Apply Microsoft Entra identity, role-based access control, network isolation, and Azure Policy to your Foundry resources.
  • Centralized operations: Monitor model usage and costs alongside your other Azure services.

Architecture overview

The GitLab Duo Self-Hosted solution consists of three core components:

  1. Self-managed GitLab instance: Your existing GitLab instance where users interact with GitLab Duo features.
  2. AI Gateway: A service that routes requests between GitLab and your chosen LLM backend.
  3. Model endpoints: One or more model deployments exposed through Microsoft Foundry.

A single AI Gateway serves every model you configure, and GitLab decides which deployment to call based on the feature that made the request:

flowchart LR
    subgraph self["Your infrastructure"]
        GL["Self-Managed<br/>GitLab"]
        GW["AI Gateway<br/>(port 5052)"]
    end

    subgraph azure["Your Azure tenant"]
        subgraph foundry["Microsoft Foundry"]
            M1["duo-chat<br/>Agentic Chat, Agent Platform"]
            M2["duo-code-gen<br/>Code generation"]
            M3["duo-code-completion<br/>Code completion"]
        end
    end

    GL -- HTTPS --> GW
    GW --> M1
    GW --> M2
    GW --> M3

Note: You can use another serving platform if you are running on-premises or using another cloud provider.

What leaves your network

This shape of deployment is what makes GitLab Duo workable for teams with data sovereignty obligations, so it's worth being precise about where data travels.

In a fully self-hosted configuration, GitLab's documentation states that inference data — code inputs, model prompts, and model responses — does not leave your network. Requests go from your GitLab instance to your AI Gateway to your Foundry deployment, all within infrastructure you control. GitLab also does not capture which model or model provider you use.

What does leave, on an online license, is billing metadata: an instance ID, a de-identified user ID, a call count, and a timestamp. On an offline license, your instance doesn't connect to GitLab's billing components at all.

Two conditions attach to that:

  • It applies only to features backed by your own models. If you route a feature to a GitLab-managed model, that feature's requests go to the GitLab-hosted AI Gateway instead, and the deployment is hybrid rather than fully self-hosted.
  • Within Azure, residency depends on deployment type. Data at rest stays in the Azure geography you choose, but where inferencing runs depends on whether you pick a global, data zone, or regional deployment. This is the setting to get right if you have jurisdictional requirements.

Where GitLab support and the Foundry catalog overlap

Choosing a model means satisfying two independent constraints: GitLab must support it, and Foundry must offer it. Neither implies the other.

GitLab rates each supported model against four capability areas: code completion, code generation, GitLab Duo Agentic Chat, and GitLab Duo Agent Platform. These families appear in both GitLab's supported-model table and the Foundry catalog:

FamilyHow Foundry offers itWhat to know
GPTSold by AzureDeepest overlap with GitLab's table; simplest path. Includes general-purpose, coding-optimized, and smaller low-latency variants
ClaudeFrom partners, via Azure MarketplaceStrong agentic ratings; extra Marketplace prerequisites and narrower region coverage
LlamaSold by Azure and from partnersRatings vary sharply by model size and feature
MistralFrom partnersIncludes Codestral, which is code-specialized

Specific version numbers move quickly on both sides, so this post deliberately avoids naming a "best" model. Instead, pick using these rules:

  • Simplest path: Choose a current general-purpose GPT model rated full functionality in all four areas.
  • Ratings are per feature, not per family: This is a model that is excellent for GitLab Duo Agentic Chat can be rated limited for code completion. Check each feature you plan to enable rather than assuming a family is uniformly strong.
  • Newer is not automatically supported: Foundry ships releases ahead of GitLab's matrix, and also carries families such as Grok, DeepSeek, and Phi that are not in GitLab's supported list. Use those only after GitLab adds them, or evaluate them under GitLab's compatible-models beta, which accepts any model exposed through an OpenAI-compatible endpoint.
  • Older GPT-4 era models still appear in GitLab's table but are not the best starting point for a new deployment.

Always confirm current ratings in GitLab's supported models page before you commit, and treat any model named in this post as an example rather than a recommendation.

Prerequisites

Before we begin, you'll need:

  • A GitLab Premium or Ultimate Self-Managed instance. GitLab Duo Self-Hosted has been generally available since GitLab 17.9, but individual features have their own minimums, and GitLab Duo Agent Platform Self-Hosted requires a considerably later release. Check the feature versions table for the features you plan to enable, and prefer a recent release for current model support.
  • The applicable GitLab Duo add-on for your deployment.
  • Administrator access to GitLab.
  • An Azure subscription with access to Microsoft Foundry.
  • Quota for each model you plan to deploy, in a supported Azure region and deployment type. Check region availability for models sold by Azure or models from partners first.
  • For partner models such as Claude or Mistral, an Azure subscription eligible for Marketplace purchases and the required Marketplace permissions. Student, free-trial, and credit-only subscriptions are not supported.
  • A local AI Gateway installed according to the GitLab installation documentation.

Note: If you aren't a GitLab customer yet, you can start a free trial of GitLab Ultimate.

Implementation steps

1. Deploy one or more models in Microsoft Foundry

Open the Foundry portal, select your project, and deploy your chosen models from the catalog. Model availability varies by region, cloud, and deployment type, and some subscriptions require an approved quota increase.

Before you deploy, confirm your model is offered in the region and deployment type you intend to use. Microsoft publishes this in Region availability for Foundry Models sold by Azure, with separate tabs for standard, provisioned, and batch. Coverage is uneven: a model can be broadly available as Global Standard yet offered in only a handful of regions as Regional Provisioned Managed.

Partner models are more constrained than Azure OpenAI models. Claude, for example, is concentrated in a small number of regions, and deploying it requires accepting Marketplace terms. Verify both region and subscription eligibility before committing to a family.

Microsoft Foundry models

Give each deployment a name you can trace later. GitLab references the deployment name rather than the catalog model name, so a vague name is hard to audit.

Naming by role rather than by model version, such as duo-chat or duo-code-completion, has a practical advantage: when you upgrade to a newer model, you can point the deployment at it without editing the model identifier in GitLab. Naming by version, such as duo-gpt-5-2, is more explicit but means reconfiguring GitLab on every model change.

If you're starting out, deploy a single model and expand once it works end to end.

After deployment, record these values for each deployment:

  • The endpoint URL
  • The deployment name
  • An API key with access to the deployment

Microsoft Foundry - gpt-5-mini model

Use a secret-management process approved by your organization. Do not commit the API key to a repository.

2. Install the AI Gateway

The AI Gateway routes requests between GitLab and the selected model endpoint. Install it with Docker or the Helm chart by following the current AI Gateway installation guide.

Avoid copying an old image tag or API-version example from another tutorial. The AI Gateway and GitLab versions should remain compatible, and GitLab's installation guide provides the current image and required settings. The Foundry endpoint and API key are entered when you add each model to GitLab in step 4; they do not need to be embedded in the example Docker command.

One gateway serves every model you configure, so you don't need a separate gateway per deployment or per model family.

3. Configure GitLab to access the AI Gateway

Now that the AI gateway is running, configure your GitLab instance to use it:

  • On the left sidebar, at the bottom, select Admin.
  • Select GitLab Duo.
  • In the GitLab Duo section, select Change configuration.
  • Under Local AI Gateway URL, enter the URL for your AI gateway and port (e.g., https://ai-gateway.example.com:5052).
  • Select Save changes.

GitLab Duo - AIGW configuration

For production deployments, use TLS and restrict network access to the gateway. If the gateway uses a private IP address or internal hostname, add it to GitLab's outbound-request allowlist.

4. Add each deployment to GitLab

Repeat this procedure once per Foundry deployment you want GitLab to use.

  • In the upper-right corner, select Admin.
  • In the left sidebar, select GitLab Duo.
  • Select Configure models for GitLab Duo.
  • Select Add self-hosted model.
  • Complete the fields:
    • Deployment name: Enter a recognizable name, such as Agentic Chat on Microsoft Foundry.
    • Model family: Select the family that matches the model, such as GPT or Claude.
    • Endpoint: Enter the endpoint URL from your Foundry deployment.
    • API key: Enter the API key for the deployment.
    • Model identifier: Enter azure/YOUR-DEPLOYMENT-NAME, using the exact deployment name from Foundry. For example, azure/duo-chat.
  • Select Add self-hosted model.

GitLab Duo - self-hosted model configuration (gpt-5-codex)

The prefix describes how a model is served, not who built it. Foundry can expose non-OpenAI models through the Azure OpenAI endpoint, in which case azure/ still applies. If you deploy a partner model that you reach through a different Foundry endpoint, confirm the correct prefix in GitLab's configuration documentation rather than assuming. A mismatched prefix produces the "Model not found" error described below.

5. Assign models to GitLab Duo features

  • In Admin > GitLab Duo, select Configure models for GitLab Duo.
  • Select the AI-native features tab.
  • For each feature you want to route to Foundry, select a deployment from the dropdown list.

This is where the breadth of the catalog pays off, because features do not have to share one model or even one family. One reasonable split:

  • Code completion: a smaller, faster model from the family you chose, where request volume is high and latency is most visible.
  • Code generation: a code-specialized model, such as a Codex or Codestral variant.
  • GitLab Duo Agentic Chat: a broadly capable general-purpose model. If you don't set a model for an individual chat sub-feature, it inherits the model configured for General Chat in the Admin area.
  • GitLab Duo Agent Platform: any model rated full functionality for Agent Platform in GitLab's matrix. Smaller models are often rated lower here than they are for completion and chat.

GitLab Duo - model selection

Treat that split as a starting hypothesis rather than a tuned configuration. Begin with a single model across the features you plan to enable so you have a clean quality, latency, and cost baseline, then introduce a second model only where your own measurements justify it.

Verifying your setup

To ensure that your GitLab Duo Self-Hosted implementation with Microsoft Foundry is working correctly, perform these verification steps:

1. Run the health check

After running the health check of your model to be sure that it's up and running, return to the GitLab Duo section from the Admin page and click on Run health check. This will verify if:

  • The AI gateway URL is properly configured.
  • Your instance can connect to the AI gateway.
  • The required GitLab Duo add-on is active.
  • A model is assigned to Code Suggestions — as this is the model used to test the connection.

If the health check reports issues, refer to the troubleshooting guide for common errors.

2. Scaffold a FastAPI service with code generation

Code generation is a good first test because it exercises the whole path end to end and produces an unmistakable result. It also sends more context than code completion, so a misconfigured endpoint or an undersized quota shows up immediately.

Code Suggestions has two distinct behaviors, and knowing which one you're triggering matters when you interpret the result:

  • Code completion fires as you type and finishes the current line. Low latency, usually under a second.
  • Code generation fires when you press Enter after a comment describing what you want. It can return whole functions or classes, and may take more than five seconds.

To scaffold a FastAPI service:

  1. Open a project in your IDE and create an empty file, such as main.py. Code generation is more accurate when the file has fewer than five lines, so an empty file is the ideal starting point.
  2. Write a comment that names the framework and states the outcome you want:
    # Create a FastAPI service with a health check endpoint and CRUD endpoints for
    # a "tasks" resource backed by an in-memory list. Use Pydantic models for
    # request and response bodies, and return appropriate HTTP status codes.
    
  3. Press Enter after the comment. The trailing newline signals that your instructions are complete.
  4. Wait for the suggestion, then press Tab to accept it or Esc to reject it.

Code generation - scaffold fast-api

Naming the framework explicitly is what makes this work. GitLab's guidance for code generation is to state the outcome, stay specific but concise, and name the library or framework you want. A vaguer comment such as # web service gives the model far less to work with.

Two things to expect. Code generation output is capped at roughly 2048 tokens, so you'll get a solid scaffold rather than a finished application. And because these models are non-deterministic, the same comment won't produce identical code twice, which is normal rather than a sign of misconfiguration.

If you assigned different models to different features, test them separately so a failure points at one deployment. Confirming code generation also confirms that the model you mapped to Code generation in Step 5 is the one actually serving the request.

3. Check AI Gateway logs

Review the AI gateway logs to see requests being routed to your Microsoft Foundry deployments:

In your terminal, run:

docker logs gitlab-ai-gateway --tail 100 -f

You should see log entries indicating successful requests to the configured model endpoint. Avoid enabling prompt logging unless your organization's data-handling policy permits it.

Next steps

Here are the next steps to take.

Keep model selection current

The GitLab team actively tests each model's performance for each feature and provides tier ranking of model's performance and suitability:

  • Full functionality: The model can likely handle the feature without any loss of quality.
  • Partial functionality: The feature works, but there might be compromises or limitations.
  • Limited functionality: The model is unsuitable for the feature and might produce significant quality loss or performance issues.

Do not infer compatibility from the model name or from its presence in the Foundry catalog. Use GitLab's models and hardware requirements page as the source of truth for GitLab's current ratings.

Cost optimization strategies:

  • Begin with a single model rated full in all four areas across the features you plan to enable.
  • Measure quality, latency, token use, rate-limit behavior, and cost with representative workloads.
  • Move high-volume features such as code completion to a smaller model once you have confirmed the quality trade-off is acceptable, and check its GitLab Duo Agent Platform rating before reusing it there.
  • Consider a code-specialized model for Code Suggestions if generation quality matters more than cost for your teams.
  • Review the GitLab support matrix and Microsoft's model-retirement schedule regularly.
  • Monitor consumption through Azure Cost Management and configure budgets or alerts appropriate to your organization.

Going beyond Microsoft Foundry

While this guide focuses on Microsoft Foundry integration, GitLab Duo Self-Hosted supports multiple deployment options:

  1. On-premises with vLLM: Serve a supported or OpenAI API-compatible model on infrastructure you manage.
  2. Amazon Bedrock: Similar to Microsoft Foundry, you can use Amazon Bedrock for cloud-hosted models.
  3. Other validated providers, including Anthropic, OpenAI, and Gemini Enterprise Agent Platform.

Enterprise integration with Azure

Microsoft Foundry offers unique advantages for organizations already invested in the Azure ecosystem:

  • Unified billing: Track model consumption with your other Azure services.
  • Microsoft Entra integration: Apply existing identity and role-management practices to Foundry resources.
  • Private networking: Evaluate private endpoints and your GitLab-to-Azure network path based on your security architecture.
  • Regional deployment: Choose among the regions and deployment types where the selected model is available, keeping in mind the residency distinction described earlier.

These capabilities can support a compliance program, but they do not make a GitLab Duo deployment compliant by themselves. Validate the complete architecture, data flows, logging, retention, contracts, and operational controls against your requirements.

Summary

GitLab Duo Self-Hosted with Microsoft Foundry lets organizations serve GitLab Duo features from Azure-hosted models. Because Foundry's catalog spans GPT, Claude, Llama, and Mistral, and GitLab supports models from each, one Azure subscription can cover the families you need. Start with one broadly capable model, then assign different models to different features as your measurements justify.

Model names in this post are examples, not recommendations. Both catalogs change frequently, so treat the two vendor matrices as the source of truth at the time you deploy.

The durable lesson is to treat model selection as a compatibility decision, not a catalog-shopping exercise. Check GitLab's support matrix, confirm availability and lifecycle status in Microsoft Foundry, deploy the models, and then validate them with your own workloads before broad rollout.

Get started

Read the whole story
alvinashcraft
48 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Why I Finally Switched from Fiddler Classic to Fiddler Everywhere

1 Share

One power user explains why HTTP/2 support pushed him over the edge to upgrade to Fiddler Everywhere.

I have been using Fiddler for more than 20 years. I rely on it daily to identify issues, troubleshoot problems, review performance, and understand how websites work. It is amazing the difference it makes when you can see exactly how web browsers and servers communicate, and what they send and receive.

When Fiddler Everywhere was first introduced to the Progress Telerik toolset, I continued to use Fiddler Classic primarily because I did not need a cross-platform solution and Fiddler Everywhere did not yet have some of the advanced functionality I relied on. I was happy where I was with Classic.

Eventually, as features were added to Fiddler Everywhere, I started to use it more often. Fiddler Everywhere also introduced features that Classic didn’t have, but those were also not primary features I needed, so I wasn’t yet a full convert. The tipping point for me transitioning to Everywhere was the impact of a new protocol HTTP/2.

What Is Protocol HTTP/2 vs. HTTP/1.1?

Let’s start by defining what a protocol is. A protocol is a set of rules that describe how participants communicate with one another. Prior to HTTP/2, the protocol for how browsers and servers communicate was HTTP/1.1.

In the world of computers, some things change very rapidly like new JavaScript frameworks or lately AI. HTTP protocol updates move more slowly.

HTTP/1.1 was introduced in 1999, and it was a HUGE success! It shouldered the burden of supporting all of the websites we used every day. Webpages typically require about 100 requests from an array of different hosts. HTTP/1.1 specified that browsers should open up to 2 connections to each host. Gradually modern browsers coalesced on using 6 connections per host, and each connection could handle a single request/response at a time.

That meant that if the webpage needed 30 files (images, CSS, JavaScript, etc.) from a single host, it would need to do that in sets of 6. This would limit how quickly the page could get the necessary files and show the webpage. Since it only supported a single request/response per connection, if a given file was taking a long period of time, that would limit the number of available connections for additional files. Another concern is that creating these connections takes time to start and become fully functional (lookup TCP “3-way handshake” and “slow start” for more details).

A very simple webpage demonstration is HTML that requests 10 images. In Fiddler Classic, I used the AutoResponder to create a rule that simulates a slow connection by intentionally delaying each JPG request by 8 seconds:

Fiddler Classic delay by 8 seconds

When the webpage is requested, you can see that with a limited number of connections and only a single request and response on each connection how the performance of the webpage is impacted (a typical “staircase” timeline):

Fiddler Classic staircase timeline

That eventually became a problem for me because the behavior I saw in Fiddler Classic was no longer the behavior users experienced in their browsers. In this example, Fiddler Classic, using the HTTP/1.1 connection, will try to open 6 connections to the host. The webpage will end up taking at least 16 seconds.

Fiddler Everywhere Support of HTTP/2 Means Better Accuracy

At last, in 2015, the World Wide Web adopted HTTP/2, which had many innovations, but the most impactful was “multiplexing,” which is a fancy way to say that each connection can handle multiple requests and responses at the same time.

This meant that browsers only needed to use a single connection per host, and that a single slow request/response doesn’t impact others. As you can imagine, a website hosted on a server that supported HTTP/2 could have a large impact on the reliability and performance of a webpage.

Support of HTTP2, which Fiddler Everywhere now offers, allows for a more accurate understanding of what actually went through the wire. The same demonstration page from above would look like this in Fiddler Everywhere:

Fiddler Everywhere does not have the same staircase appearance

Since Fiddler Everywhere supports HTTP/2, you can see that all of the images were happening at the same time, and that the page finishes now in a little more than 8 seconds.

As the adoption of HTTP/2 grew, it reached the point that I could no longer rely on Fiddler Classic to accurately represent how a website would behave, and I finally moved to using Fiddler Everywhere exclusively.


Ready to Try Fiddler Everywhere for Yourself?

Enjoy a free trial today:

Try Now

Read the whole story
alvinashcraft
49 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

More Coverage, Less Confidence

1 Share

Code coverage and test confidence should move together. But they don’t always.

Here’s a result most development teams would celebrate:

Last month:  78% code coverage
This month:  91% code coverage

↑ 13%

Nice.

Surely the test suite is getting better.

Maybe.

Now imagine what happened behind that number:

+ 146 new tests
+ 13% code coverage
+ 37 duplicate tests
+ 18 tests touching external resources
+ 2 minutes added to every CI run

The code coverage went up.

But did your test confidence go up with it?

Code Coverage Is Useful

Let’s get one thing out of the way: code coverage is a valuable engineering metric.

Typemock has provided code coverage capabilities for years, and I wouldn’t want to work on a large codebase without knowing which parts of the production code our unit tests actually execute.

If an important piece of business logic has zero coverage, that’s useful information.

If a pull request suddenly causes coverage to collapse, that’s useful information too.

The problem starts when we turn code coverage from a signal into a score.

72%  😟
84%  🙂
91%  😎
97%  🏆

Software quality isn’t quite that cooperative.

What Code Coverage and Test Confidence Actually Measure

Suppose we have this simple method:

public decimal CalculateDiscount(Customer customer)
{
    if (customer.IsPremium)
        return 0.20m;

    return 0;
}

And this unit test:

[TestMethod]
public void CalculateDiscount_Test()
{
    var customer = new Customer { IsPremium = true };

    var result = CalculateDiscount(customer);

    Assert.IsTrue(result >= 0);
}

The test executes the premium path.

Coverage goes up.

But the test doesn’t actually verify that a premium customer receives a 20% discount.

0.01, 0.10 or 0.19 would all satisfy that assertion.

Code coverage can tell us:

This code executed.

It cannot tell us:

This behavior was correctly verified.

That’s not a weakness in code coverage.

It’s simply not what coverage measures.

And that’s where code coverage and test confidence start to diverge.

More Tests Can Make the Dashboard Look Better

Now imagine someone decides the project needs more coverage.

They add another test.

Then another.

Or perhaps an AI coding assistant generates several automatically.

Soon we have:

CalculateDiscount_PremiumCustomer
CalculateDiscount_PremiumCustomer_ReturnsDiscount
CalculateDiscount_WithPremiumCustomer
PremiumCustomerGetsDiscount
CalculateDiscount_WhenPremiumIsTrue

Five tests.

Perhaps they use slightly different values or assertions, but fundamentally they exercise the same behavior.

Our numbers look excellent:

Tests:     ↑
Coverage:  ↑
Build:     ✓

But the amount of unique protection may have barely changed.

We’ve improved the dashboard without necessarily improving the safety net.

This problem is becoming more visible as AI makes generating tests increasingly cheap. I discussed the impact of duplicate unit tests in the age of AI with Software Testing Magazine.

Generating more tests is easy.

Knowing whether those tests add something useful is much harder.

More Tests Also Mean More Code to Maintain

Every additional unit test becomes code we own.

When production code changes, tests may need to change.

When a test fails, somebody has to investigate it.

When a supposedly isolated unit test depends on a file, network connection, process, environment variable or other external resource, that dependency can eventually become somebody’s mysterious CI failure.

And when several tests protect essentially the same behavior, developers may have to update all of them after one legitimate change.

So there are some important numbers that don’t appear on the code coverage report:

Maintenance cost:          ???
Unique confidence added:   ???
Developer attention:       ???

Those are much harder to measure than a percentage.

But they’re important.

When Code Coverage Goes Up but Test Confidence Goes Down

Consider two test suites.

Suite A

1,200 tests
95% code coverage
Slow
Some duplication
Several external dependencies
Frequent maintenance

Suite B

750 tests
85% code coverage
Fast
Isolated
Tests distinct behaviors
Easy to understand

Which would you rather inherit?

There’s actually not enough information to answer.

And that’s exactly the point.

Code coverage alone can’t tell us which test suite is better.

Maybe Suite A protects critical behavior that Suite B misses.

Maybe Suite B gives developers far more reliable feedback.

Maybe both have serious problems.

A percentage can’t tell us.

Code Coverage Shouldn’t Become the Goal

Imagine optimizing a development team around lines of code written.

Developers would become extremely productive:

if (x == 1) return true;
if (x == 2) return true;
if (x == 3) return true;
if (x == 4) return true;

// KPI looking fantastic...

We know that’s absurd because lines of code are an output, not the goal.

Code coverage deserves similar caution.

The goal of unit testing isn’t to maximize a percentage.

The goal is to give developers confidence to change software.

Code coverage helps us get there.

But so do:

  • meaningful assertions
  • proper test isolation
  • effective mocking
  • fast feedback
  • understandable tests
  • tests that protect distinct behavior
  • tests that fail for the right reasons

That’s a much richer definition of test quality than a single percentage.

What Happens When AI Optimizes for Coverage?

This becomes particularly interesting with AI-generated tests.

Tell an AI:

Increase code coverage to 90%.

And that’s a very measurable objective.

The AI can generate tests, run them, inspect the coverage result and keep generating until the number reaches the target.

82%
↓
Generate tests
↓
86%
↓
Generate more tests
↓
91%
↓
Mission accomplished ✓

Technically, it succeeded.

But did we ask it the right question?

Perhaps a better objective would be:

Increase meaningful protection of important application behavior.

That’s much harder to turn into a percentage.

It’s also much closer to what developers actually want.

Ask One More Question

When code coverage goes from:

82% → 91%

celebrate it.

Then ask:

Why did it go up?

Did we cover previously untested behavior?

Excellent.

Did we add important edge cases?

Great.

Did we protect against a bug that could otherwise return?

Perfect.

Or did we simply add another collection of tests that happen to execute more lines?

That’s a different result.

And that’s where code coverage and test confidence need to be considered separately.

Coverage + Test Quality

This is also one of the reasons we’re working on Typemock Test Review.

Traditional test results tell us whether tests passed.

Code coverage tells us which production code executed.

Test Review looks at tests from another direction, including whether tests duplicate existing behavior and whether supposedly isolated tests access external resources.

These are complementary signals:

Test Result  → Did the test pass?
Coverage     → What code executed?
Test Review  → What deserves attention?

No single metric can tell you whether a test suite is good.

And that’s probably how it should be.

Software engineering rarely fits neatly into one percentage.

So the next time your code coverage dashboard climbs from 82% to 91%, enjoy the green arrow.

Just don’t confuse it with confidence.

Because sometimes you can have more coverage and less confidence.

The post More Coverage, Less Confidence appeared first on Typemock.

Read the whole story
alvinashcraft
49 minutes ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories