Skip to content

Commit e5889e3

Browse files
committed
docs: wrap body text to 80 columns
1 parent 0e32f1b commit e5889e3

File tree

1 file changed

+148
-91
lines changed

1 file changed

+148
-91
lines changed

docs/architecture.md

Lines changed: 148 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -39,60 +39,78 @@
3939
+---------------------------------------+ +------------------------------------+
4040
```
4141

42-
Git Credential Manager Core (GCM Core) is built to be Git host and platform/OS agonstic.
43-
Most of the shared logic (command execution, the abstract platform subsystems, etc) can be found in the
44-
`Microsoft.Git.CredentialManager` class library (C#). The library targets .NET Standard as well as .NET Framework.
42+
Git Credential Manager Core (GCM Core) is built to be Git host and platform/OS
43+
agonstic. Most of the shared logic (command execution, the abstract platform
44+
subsystems, etc) can be found in the `Microsoft.Git.CredentialManager` class
45+
library (C#). The library targets .NET Standard as well as .NET Framework.
4546

4647
> **Note**
4748
>
48-
> The reason for also targeting .NET Framework directly is that the `Microsoft.Identity.Client`
49-
> ([MSAL.NET](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet)) library requires a .NET Framework
50-
> target to be able to show the embedded web browser auth pop-up on Windows platforms.
49+
> The reason for also targeting .NET Framework directly is that the
50+
> `Microsoft.Identity.Client` ([MSAL.NET](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet))
51+
> library requires a .NET Framework target to be able to show the embedded web
52+
> browser auth pop-up on Windows platforms.
5153
>
52-
> There are extension points that now exist in MSAL.NET meaning we can plug-in our own browser pop-up handling code
53-
> on .NET Core meaning both Windows and Mac. We haven't yet gotten around to exploring this.
54+
> There are extension points that now exist in MSAL.NET meaning we can plug-in
55+
> our own browser pop-up handling code on .NET Core meaning both Windows and
56+
> Mac. We haven't yet gotten around to exploring this.
5457
>
55-
> See [this](https://github.com/microsoft/Git-Credential-Manager-Core/issues/113) issue for more information.
56-
57-
The entry-point for GCM Core can be found in the `Git-Credential-Manager` project, a console application that targets both
58-
.NET Core and .NET Framework. This project emits the `git-credential-manager-core(.exe)` executable, and contains very little
59-
code - registration of all supported host providers and running the `Application` object found in `Microsoft.Git.CredentialManager`.
60-
61-
Providers have their own projects/assemblies that take dependencies on the `Microsoft.Git.CredentialManager` core assembly,
62-
and are dependents of the main entry point application `Git-Credential-Manager`. Code in these binaries is expected to run
63-
on all supported platforms and typically (see MSAL.NET note above) does not include any graphical user interface; they use
64-
terminal prompts only.
65-
66-
Where a provider needs some platform-specific interaction or graphical user interface, the recommended model is to have a
67-
separate 'helper' executable that the shared, core binaries shell out to. Currently the Bitbucket and GitHub providers each
68-
have a WPF (Windows only) helper executable that shows authentication prompts and messages.
69-
70-
The `Microsoft.Git.CredentialHelper.UI` project is a WPF (Windows only) assembly that contains common WPF components and styles
71-
that are shared between provider helpers on Windows.
58+
> See [this](https://github.com/microsoft/Git-Credential-Manager-Core/issues/113)
59+
> issue for more information.
60+
61+
The entry-point for GCM Core can be found in the `Git-Credential-Manager`
62+
project, a console application that targets both .NET Core and .NET Framework.
63+
This project emits the `git-credential-manager-core(.exe)` executable, and
64+
contains very little code - registration of all supported host providers and
65+
running the `Application` object found in `Microsoft.Git.CredentialManager`.
66+
67+
Providers have their own projects/assemblies that take dependencies on the
68+
`Microsoft.Git.CredentialManager` core assembly, and are dependents of the main
69+
entry point application `Git-Credential-Manager`. Code in these binaries is
70+
expected to run on all supported platforms and typically (see MSAL.NET note
71+
above) does not include any graphical user interface; they use terminal prompts
72+
only.
73+
74+
Where a provider needs some platform-specific interaction or graphical user
75+
interface, the recommended model is to have a separate 'helper' executable that
76+
the shared, core binaries shell out to. Currently the Bitbucket and GitHub
77+
providers each have a WPF (Windows only) helper executable that shows
78+
authentication prompts and messages.
79+
80+
The `Microsoft.Git.CredentialHelper.UI` project is a WPF (Windows only) assembly
81+
that contains common WPF components and styles that are shared between provider
82+
helpers on Windows.
7283

7384
### Cross-platform UI
7485

75-
We hope to be able to migrate the WPF/Windows only helpers to [Avalonia](https://avaloniaui.net/) in order to gain cross-platform
76-
graphical user interface support. See [this](https://github.com/microsoft/Git-Credential-Manager-Core/issues/136) issue for
77-
up-to-date progress on this effort.
86+
We hope to be able to migrate the WPF/Windows only helpers to [Avalonia](https://avaloniaui.net/)
87+
in order to gain cross-platform graphical user interface support. See [this](https://github.com/microsoft/Git-Credential-Manager-Core/issues/136)
88+
issue for up-to-date progress on this effort.
7889

7990
### Microsoft authentication
8091

81-
For authentication using Microsoft Accounts or Azure Active Directory, things are a little different. The `MicrosoftAuthentication`
82-
component is present in the core `Microsoft.Git.CredentialManager` assembly, rather than bundled with a specific host provider.
83-
This was done to allow any service that may wish to in the future integrate with Microsoft Accounts or Azure Active Directory can
84-
make use of this reusable authentication component.
85-
86-
Since MSAL.NET includes embedded GUI on Windows (when targeting .NET Frameonly only - see note above) we have no helper executable
87-
on Windows. However, on macOS the `MicrosoftAuthentication` component shells out to a native macOS helper that completely takes over
88-
all authentication flows using the older ADAL Objective-C libary. This was done because MSAL.NET does not offer the same level of
89-
integration for [MDM](https://en.wikipedia.org/wiki/Mobile_device_management) purposes, as well as lacking an embedded UI on non-Windows
90-
platforms. As MSAL.NET continues to evolve we hope to replace the ADAL/macOS helper altogether.
92+
For authentication using Microsoft Accounts or Azure Active Directory, things
93+
are a little different. The `MicrosoftAuthentication` component is present in
94+
the core `Microsoft.Git.CredentialManager` assembly, rather than bundled with a
95+
specific host provider. This was done to allow any service that may wish to in
96+
the future integrate with Microsoft Accounts or Azure Active Directory can make
97+
use of this reusable authentication component.
98+
99+
Since MSAL.NET includes embedded GUI on Windows (when targeting .NET Frameonly
100+
only - see note above) we have no helper executable on Windows. However, on
101+
macOS the `MicrosoftAuthentication` component shells out to a native macOS
102+
helper that completely takes over all authentication flows using the older ADAL
103+
Objective-C libary. This was done because MSAL.NET does not offer the same level
104+
of integration for [MDM](https://en.wikipedia.org/wiki/Mobile_device_management)
105+
purposes, as well as lacking an embedded UI on non-Windows platforms. As
106+
MSAL.NET continues to evolve we hope to replace the ADAL/macOS helper
107+
altogether.
91108

92109
## Asynchronous programming
93110

94-
GCM Core makes use of the `async`/`await` model of .NET and C# in almost all parts of the codebase where appropriate
95-
as usually requests end up going to the network at some point.
111+
GCM Core makes use of the `async`/`await` model of .NET and C# in almost all
112+
parts of the codebase where appropriate as usually requests end up going to the
113+
network at some point.
96114

97115
## Command execution
98116

@@ -137,62 +155,94 @@ as usually requests end up going to the network at some point.
137155
+---------------+
138156
```
139157

140-
Git Credential Manager Core maintains a set of known commands including `Get|Store|EraseCommand`, as well as commands for install and help/usage.
141-
142-
GCM Core also maintains a set of known, registered host providers that implement the `IHostProvider` interface. Providers register themselves
143-
by adding an instance of the provider to the `Application` object via the `RegisterProvider` method [in `Microsoft.Git.CredentialManager.Program`](../src/shared/Git-Credential-Manager/Program.cs).
144-
The `GenericHostProvider` is registered last so that it can handle all other HTTP-based remotes as a catch-all, and provide basic username/password
145-
auth and detect the presense of Windows Integrated Authentication (Kerberos, NTLM, Negotiate) support (1).
146-
147-
For each invocation of GCM Core, the first argument on the command-line is matched against the known commands and if there is a successful match,
148-
the input from Git (over standard input) is deserialized and the command is executed (2).
149-
150-
The `Get|Store|EraseCommand`s consult the host provider registry for the most appropriate host provider. The default registry implementation select
151-
the a host provider by asking each registered provider in turn if they understand the request. The provider selection can be overriden by the user
152-
via the [`credential.provider`](configuration.md#credentialprovider) or [`GCM_PROVIDER`](environment.md#GCM_PROVIDER) configuration and environment
153-
variable respectively (3)).
154-
155-
The `Get|Store|EraseCommand`s call the corresponding `Get|Store|EraseCredentialAsync` methods on the `IHostProvider`, passing the request from Git
156-
together with an instance of the `ICommandContext` (4). The host provider can then make use of various services available on the command context to
157-
complete the requested operation (5).
158-
159-
Once a credential has been created, retrieved, stored or erased, the host provider returns the credential (for `get` operations only) to the calling
160-
command (6). The credential is then serialized and returned to Git over standard output (7) and GCM Core terminates with a successful exit code.
158+
Git Credential Manager Core maintains a set of known commands including
159+
`Get|Store|EraseCommand`, as well as commands for install and help/usage.
160+
161+
GCM Core also maintains a set of known, registered host providers that implement
162+
the `IHostProvider` interface. Providers register themselves by adding an
163+
instance of the provider to the `Application` object via the `RegisterProvider`
164+
method [in `Microsoft.Git.CredentialManager.Program`](../src/shared/Git-Credential-Manager/Program.cs).
165+
The `GenericHostProvider` is registered last so that it can handle all other
166+
HTTP-based remotes as a catch-all, and provide basic username/password auth and
167+
detect the presense of Windows Integrated Authentication (Kerberos, NTLM,
168+
Negotiate) support (1).
169+
170+
For each invocation of GCM Core, the first argument on the command-line is
171+
matched against the known commands and if there is a successful match, the input
172+
from Git (over standard input) is deserialized and the command is executed (2).
173+
174+
The `Get|Store|EraseCommand`s consult the host provider registry for the most
175+
appropriate host provider. The default registry implementation select the a host
176+
provider by asking each registered provider in turn if they understand the
177+
request. The provider selection can be overriden by the user via the
178+
[`credential.provider`](configuration.md#credentialprovider) or [`GCM_PROVIDER`](environment.md#GCM_PROVIDER)
179+
configuration and environment variable respectively (3)).
180+
181+
The `Get|Store|EraseCommand`s call the corresponding
182+
`Get|Store|EraseCredentialAsync` methods on the `IHostProvider`, passing the
183+
request from Git together with an instance of the `ICommandContext` (4). The
184+
host provider can then make use of various services available on the command
185+
context to complete the requested operation (5).
186+
187+
Once a credential has been created, retrieved, stored or erased, the host
188+
provider returns the credential (for `get` operations only) to the calling
189+
command (6). The credential is then serialized and returned to Git over standard
190+
output (7) and GCM Core terminates with a successful exit code.
161191

162192
## Host provider
163193

164-
Host providers implement the `IHostProvider` interface. They can choose to directly implement the interface they can also derive from the `HostProvider`
194+
Host providers implement the `IHostProvider` interface. They can choose to
195+
directly implement the interface they can also derive from the `HostProvider`
165196
abstract class (which itself implements the `IHostProvider` interface).
166197

167-
The `HostProvider` abstract class implements the `Get|Store|EraseCredentialAsync` methods and instead has a `GenerateCredentialAsync` and
168-
`GetCredentialKey` abstract methods. Calls to `get`, `store`, or `erase` result in first a call to `GetCredentialKey` which should return a stable and
169-
unique "key" for the request. This forms the key for any stored credential in the credential store. During a `get` operation the credential store is queried
170-
for an existing credential with the computed key. If a credential is found it is returned immediately. Similarly, calls to `store` and `erase` are handles
171-
automatically to store credentials against, and erase credentials matching the computed key. Methods are implemented as `virtual` meaning you can always
172-
override this behaviour, for example to clear other custom caches on an `erase` request, without having to reimplement the lookup/store credential logic.
173-
174-
Host providers are queried in turn (registration order) via the `IHostProvider.IsSupported` method and passed the input recieved from Git.
175-
If the provider recognises the request, for example by a matching known host name, they can return `true`. If the provider wants to cancel and abort
176-
an authentication request, for example if this is a HTTP (not HTTPS) request for a known host, they should still return `true` and later cancel the request.
177-
178-
Depending on the request from Git, one of `GetCredentialAsync` (for `get` requests), `StoreCredentialAsync` (for `store` requests) or
179-
`EraseCredentialAsync` (for `erase` requests) will be called. The argument `InputArguments` contains the request information passed over standard input
198+
The `HostProvider` abstract class implements the
199+
`Get|Store|EraseCredentialAsync` methods and instead has a
200+
`GenerateCredentialAsync` and `GetCredentialKey` abstract methods. Calls to
201+
`get`, `store`, or `erase` result in first a call to `GetCredentialKey` which
202+
should return a stable and unique "key" for the request. This forms the key for
203+
any stored credential in the credential store. During a `get` operation the
204+
credential store is queried for an existing credential with the computed key.
205+
If a credential is found it is returned immediately. Similarly, calls to `store`
206+
and `erase` are handles automatically to store credentials against, and erase
207+
credentials matching the computed key. Methods are implemented as `virtual`
208+
meaning you can always override this behaviour, for example to clear other
209+
custom caches on an `erase` request, without having to reimplement the
210+
lookup/store credential logic.
211+
212+
Host providers are queried in turn (registration order) via the
213+
`IHostProvider.IsSupported` method and passed the input recieved from Git. If
214+
the provider recognises the request, for example by a matching known host name,
215+
they can return `true`. If the provider wants to cancel and abort an
216+
authentication request, for example if this is a HTTP (not HTTPS) request for a
217+
known host, they should still return `true` and later cancel the request.
218+
219+
Depending on the request from Git, one of `GetCredentialAsync` (for `get`
220+
requests), `StoreCredentialAsync` (for `store` requests) or
221+
`EraseCredentialAsync` (for `erase` requests) will be called. The argument
222+
`InputArguments` contains the request information passed over standard input
180223
from Git/the caller; the same as was passed to `IsSupported`.
181224

182-
The return value for the `get` operation must be an `ICredential` that Git can use to complete authentication.
225+
The return value for the `get` operation must be an `ICredential` that Git can
226+
use to complete authentication.
183227

184228
> **Note:**
185229
>
186-
> The credential can also be an instance where both username and password are the empty string, to signal to Git it
187-
> should let cURL use "any auth" detection - typically to use Windows Integrated Authentication.
230+
> The credential can also be an instance where both username and password are
231+
> the empty string, to signal to Git it should let cURL use "any auth"
232+
> detection - typically to use Windows Integrated Authentication.
188233
189-
There are no return values for the `store` and `erase` operations as Git ignores any output or exit codes for these commands. Failures for these operations
190-
are best communicated via writing to the Standard Error stream via `ICommandContext.Streams.Error`.
234+
There are no return values for the `store` and `erase` operations as Git ignores
235+
any output or exit codes for these commands. Failures for these operations are
236+
best communicated via writing to the Standard Error stream via
237+
`ICommandContext.Streams.Error`.
191238

192239
## Command context
193240

194-
The `ICommandContext` which contains numerous services which are useful for interacting with various platform subsystems, such as the file system or environment
195-
variables. All services on the command context are exposed as interfaces for ease of testing and portability between different operating systems and platforms.
241+
The `ICommandContext` which contains numerous services which are useful for
242+
interacting with various platform subsystems, such as the file system or
243+
environment variables. All services on the command context are exposed as
244+
interfaces for ease of testing and portability between different operating
245+
systems and platforms.
196246

197247
Component|Description
198248
-|-
@@ -210,13 +260,20 @@ SystemPrompts|Provides services for showing system/OS native credential prompts.
210260

211261
## Error handling and tracing
212262

213-
GCM Core operates a 'fail fast' approach to unrecoverable errors. This usually means throwing an `Exception` which will propagate up to the entry-point and
214-
be caught, a non-zero exit code returned, and the error message printed with the "fatal:" prefix. For errors originating from interop/native code, you should
215-
throw an exception of the `InteropException` type. Error messages in exceptions should be human readable. When there is a known or user-fixable issue, instructions
216-
on how to self-rememdy the issue, or links to relevant documentation should be given.
217-
218-
Warnings can be emitted over the standard error stream (`ICommandContext.Streams.Error`) when you want to alert the user to a potential issue with their
219-
configuration that does not necessarily stop the operation/authentication.
220-
221-
The `ITrace` component can be found on the `ICommandContext` object or passed in directly to some constructors. Verbose and diagnostic information is be written
263+
GCM Core operates a 'fail fast' approach to unrecoverable errors. This usually
264+
means throwing an `Exception` which will propagate up to the entry-point and be
265+
caught, a non-zero exit code returned, and the error message printed with the
266+
"fatal:" prefix. For errors originating from interop/native code, you should
267+
throw an exception of the `InteropException` type. Error messages in exceptions
268+
should be human readable. When there is a known or user-fixable issue,
269+
instructions on how to self-rememdy the issue, or links to relevant
270+
documentation should be given.
271+
272+
Warnings can be emitted over the standard error stream
273+
(`ICommandContext.Streams.Error`) when you want to alert the user to a potential
274+
issue with their configuration that does not necessarily stop the
275+
operation/authentication.
276+
277+
The `ITrace` component can be found on the `ICommandContext` object or passed in
278+
directly to some constructors. Verbose and diagnostic information is be written
222279
to the trace object in most places of GCM Core.

0 commit comments

Comments
 (0)