ldo-go was checked against the Python ldo side by side: the same commands against the same
tenant, instance and files, and the same fixtures in the tests. Tables, CSV, KQL, YAML, the
json command, Terraform files and READMEs, rewritten Logic App definitions and Message
Center tasks come out byte for byte the same; JSON records hold the same keys and values; and
self-test gives every command the same result in both. What differs is below.
- Pure Go. Every sign-in is Microsoft's own Go libraries: azidentity for the Azure CLI,
client secrets, workload identity and managed identity, and MSAL for a person's device code
or browser sign-in. A
device-codeorinteractiveprofile needs no Azure CLI at all. - No app of your own needed. Without a
client_id, adevice-codeorinteractiveprofile signs in as the Azure CLI's public client, with the Azure CLI's scopes. The Pythonldoneeds aclient_idfor either. - No offer to sign in again mid-command. When a sign-in lapses, the error names the cause
and what to run; the Python
ldooffers, on a terminal, to sign the Azure CLI back in and carry on (LDO_REAUTH).ldo-gohas no such prompt. - No keychain.
token_cache = "keychain"is taken, and the sign-in kept in the file. - Its own sign-ins. They are kept in
ldo-go-sign-ins.json, beside the Pythonldo's file rather than in it, so neither tool reads the other's refresh tokens.
- Key order. A record's keys come out sorted, where the Python
ldokeeps the order the service sent, or its own. The keys, their types and their values are the same, andinternal/cli/testdata/json-output.jsonrecords every command's shape as the Python'sjson_output.jsondoes. Where a file is written back (a Logic App export), the order is kept. - Times. A timestamp ends in
Z(2026-09-24T12:00:00Z), where Python'sisoformat()writes+00:00. Both are RFC 3339 in UTC.
- Certificates. Go verifies against the machine's own store (where IT installs a
TLS-inspecting proxy's root), with
ca_bundleadded, and has no public roots of its own, as the Pythonldohas from certifi.network testsays so: itsCertificatesline reads "this machine's store", and its JSON hassystem_storeandextra(the certificatesca_bundleadds) in place of the Python'spublic,systemandextracounts. The Azure CLI, which trusts one file alone, is still handed a bundle of the machine's certificates andca_bundle's, as the Python hands it. - The operating system's proxy setting (Windows and macOS) is not read: name the proxy
with
LDO_PROXY_ADDRESS,proxyorHTTPS_PROXY. - A certificate that does not verify.
network testnames its issuer from the certificate Go hands back with the error, rather than connecting a second time as the Python does, and says so when a server answershttpsin plain HTTP.
OTLP records carry the message, its level, the attributes and the trace context as the
Python's do, but not the Python's code.function.name, code.line.number or exception.*
attributes.
- Help.
--helpis cobra's, not Typer's panels; the text is the same. - The
jsoncommand's errors. A document that is not JSON is reported with Go's own words for why, at the same line and column. - Case. Sorting and matching fold case the way Go's
strings.ToLowerdoes, which agrees with Python'scasefoldfor everything but a few letters such asß. - Line ends. A Terraform file is split on
\n(and so\r\n); Python'ssplitlinesalso splits on rarer line breaks such as a form feed.
- No library. The Python
ldocan be imported;ldo-go's packages areinternal, so it is a command and nothing else. - No container images or packages. A release carries a binary for each platform, which
needs nothing installed beside it;
go installworks too. - No rebrand. The Python's
just rebrandrenames the whole project. Here every name lives ininternal/core/brand, so a copy under another name changes that file, but no recipe does it for you. - No GitLab mirror. The Python's repository is mirrored to GitLab and has a GitLab CI of its own; this one has GitHub's workflows only.