nitlsconfig 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2022, National Instruments Corp.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included
12
+ in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.3
2
+ Name: nitlsconfig
3
+ Version: 1.0.0
4
+ Summary: Python API for reading nitlsconfig configurations and creating NI gRPC Device client channels from them
5
+ License: MIT
6
+ Keywords: nitlsconfig,tls,mtls,grpc,configuration
7
+ Author: NI
8
+ Author-email: opensource@ni.com
9
+ Maintainer: Philip Thong
10
+ Maintainer-email: philip.thong@emerson.com
11
+ Requires-Python: >=3.9
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Operating System :: POSIX
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Provides-Extra: grpc
25
+ Requires-Dist: grpcio (>=1.49.0,<2.0) ; extra == "grpc"
26
+ Requires-Dist: pywin32 (>=306) ; (sys_platform == "win32") and (extra == "grpc")
27
+ Project-URL: Documentation, https://nitlsconfig-python.readthedocs.io
28
+ Project-URL: Repository, https://github.com/ni/nitlsconfig-python
29
+ Description-Content-Type: text/markdown
30
+
31
+ # nitlsconfig
32
+
33
+ Python API that reads nitlsconfig configurations through the `nitlsconfig` command line,
34
+ and builds NI gRPC Device client channels from them.
35
+
36
+ Installed and imported as `nitlsconfig`; developed at
37
+ [ni/nitlsconfig-python](https://github.com/ni/nitlsconfig-python).
38
+
39
+ ## Runtime dependencies
40
+
41
+ - nitlsconfig executable, discoverable.
42
+
43
+ ## Install
44
+
45
+ Reading NI TLS configuration is pure Python and has no third-party dependencies:
46
+
47
+ - `pip install nitlsconfig`
48
+
49
+ The gRPC channel factory additionally needs grpcio, which is an optional extra:
50
+
51
+ - `pip install nitlsconfig[grpc]`
52
+
53
+ Neither install provides the `nitlsconfig` runtime itself. This package reads
54
+ configuration by invoking the `nitlsconfig` command line interface, which ships with NI
55
+ driver software products that support NI TLS. Install a driver that provides it before using
56
+ this package; without it, calls raise `ExecutableNotFoundError`.
57
+
58
+ ## Creating a gRPC channel
59
+
60
+ `create_grpc_device_channel` reads the local NI TLS client configuration for the NI
61
+ gRPC Device Server and returns a `grpc.Channel` secured accordingly. The
62
+ `server_address` hostname or address is used to select matching target-specific NI TLS
63
+ settings. Pass the channel straight to any NI gRPC Python API:
64
+
65
+ ```python
66
+ import nidcpower
67
+ import nitlsconfig
68
+
69
+ with nitlsconfig.create_grpc_device_channel("localhost", 31763) as channel:
70
+ options = nidcpower.GrpcSessionOptions(channel, "")
71
+ with nidcpower.Session("Dev1", grpc_options=options) as session:
72
+ ...
73
+ ```
74
+
75
+ NI driver software provides the NI TLS configuration. Using `create_grpc_device_channel`
76
+ opts into mTLS.
77
+
78
+ Before `create_grpc_device_channel` can succeed, use NI Hardware Manager to perform a
79
+ certificate exchange with the remote system. See
80
+ [Managing mTLS](https://www.ni.com/docs/en-US/bundle/hardwaremanager/page/mtls-manage.html)
81
+ for details.
82
+
83
+ Weakening the security posture to one-way TLS or to an insecure connection
84
+ requires explicitly changing that configuration in NI Hardware Manager. Either way, no
85
+ code change is needed.
86
+
87
+ The channel is owned by the caller - NI driver APIs never close it.
88
+
89
+ Retries are opt-in:
90
+
91
+ ```python
92
+ channel = nitlsconfig.create_grpc_device_channel(
93
+ "localhost", 31763, retry_policy=nitlsconfig.RetryPolicy()
94
+ )
95
+ ```
96
+
97
+ `TlsConfigurationError` is raised when TLS is enabled but the configuration is
98
+ unusable. It is always importable, since handling it does not require grpcio.
99
+
100
+ `create_grpc_device_channel` and `RetryPolicy` do require grpcio; accessing them
101
+ without the `grpc` extra installed raises `ImportError` telling you which extra
102
+ to install.
103
+
104
+ ## Reading configurations
105
+ ```python
106
+ import nitlsconfig
107
+
108
+ # List configured services
109
+ clients = nitlsconfig.ClientConfig.list_services()
110
+ servers = nitlsconfig.ServerConfig.list_services()
111
+
112
+ if clients:
113
+ # Read one client configuration
114
+ client_info = nitlsconfig.ClientConfig(clients[0])
115
+ print(client_info.service_name)
116
+ print(client_info.certificate_mode)
117
+ print(client_info.certificate_chain_location.scheme)
118
+ print(client_info.certificate_chain_location.path)
119
+ print(client_info.certificate_chain_contents)
120
+
121
+ # Inspect target-specific configurations
122
+ for known_server in client_info.known_servers:
123
+ print(known_server.server_name)
124
+ print(known_server.server_mode)
125
+ print(known_server.trusted_certificates_location)
126
+
127
+ if servers:
128
+ # Read one server configuration
129
+ server_info = nitlsconfig.ServerConfig(servers[0])
130
+ print(server_info.service_name)
131
+ print(server_info.certificate_mode)
132
+ print(server_info.client_mode)
133
+ print(server_info.certificate_chain_location.scheme)
134
+ print(server_info.certificate_key_location.scheme)
135
+ print(server_info.trusted_certificates_location.scheme)
136
+ print(server_info.trusted_certificates_contents)
137
+
138
+ # Enumerate trusted certificates
139
+ for cert in server_info.trusted_certificates:
140
+ print(cert.display_name)
141
+ print(cert.trusted_certificate_location.path)
142
+ print(cert.trusted_certificate_contents)
143
+ ```
144
+
145
+
146
+
@@ -0,0 +1,115 @@
1
+ # nitlsconfig
2
+
3
+ Python API that reads nitlsconfig configurations through the `nitlsconfig` command line,
4
+ and builds NI gRPC Device client channels from them.
5
+
6
+ Installed and imported as `nitlsconfig`; developed at
7
+ [ni/nitlsconfig-python](https://github.com/ni/nitlsconfig-python).
8
+
9
+ ## Runtime dependencies
10
+
11
+ - nitlsconfig executable, discoverable.
12
+
13
+ ## Install
14
+
15
+ Reading NI TLS configuration is pure Python and has no third-party dependencies:
16
+
17
+ - `pip install nitlsconfig`
18
+
19
+ The gRPC channel factory additionally needs grpcio, which is an optional extra:
20
+
21
+ - `pip install nitlsconfig[grpc]`
22
+
23
+ Neither install provides the `nitlsconfig` runtime itself. This package reads
24
+ configuration by invoking the `nitlsconfig` command line interface, which ships with NI
25
+ driver software products that support NI TLS. Install a driver that provides it before using
26
+ this package; without it, calls raise `ExecutableNotFoundError`.
27
+
28
+ ## Creating a gRPC channel
29
+
30
+ `create_grpc_device_channel` reads the local NI TLS client configuration for the NI
31
+ gRPC Device Server and returns a `grpc.Channel` secured accordingly. The
32
+ `server_address` hostname or address is used to select matching target-specific NI TLS
33
+ settings. Pass the channel straight to any NI gRPC Python API:
34
+
35
+ ```python
36
+ import nidcpower
37
+ import nitlsconfig
38
+
39
+ with nitlsconfig.create_grpc_device_channel("localhost", 31763) as channel:
40
+ options = nidcpower.GrpcSessionOptions(channel, "")
41
+ with nidcpower.Session("Dev1", grpc_options=options) as session:
42
+ ...
43
+ ```
44
+
45
+ NI driver software provides the NI TLS configuration. Using `create_grpc_device_channel`
46
+ opts into mTLS.
47
+
48
+ Before `create_grpc_device_channel` can succeed, use NI Hardware Manager to perform a
49
+ certificate exchange with the remote system. See
50
+ [Managing mTLS](https://www.ni.com/docs/en-US/bundle/hardwaremanager/page/mtls-manage.html)
51
+ for details.
52
+
53
+ Weakening the security posture to one-way TLS or to an insecure connection
54
+ requires explicitly changing that configuration in NI Hardware Manager. Either way, no
55
+ code change is needed.
56
+
57
+ The channel is owned by the caller - NI driver APIs never close it.
58
+
59
+ Retries are opt-in:
60
+
61
+ ```python
62
+ channel = nitlsconfig.create_grpc_device_channel(
63
+ "localhost", 31763, retry_policy=nitlsconfig.RetryPolicy()
64
+ )
65
+ ```
66
+
67
+ `TlsConfigurationError` is raised when TLS is enabled but the configuration is
68
+ unusable. It is always importable, since handling it does not require grpcio.
69
+
70
+ `create_grpc_device_channel` and `RetryPolicy` do require grpcio; accessing them
71
+ without the `grpc` extra installed raises `ImportError` telling you which extra
72
+ to install.
73
+
74
+ ## Reading configurations
75
+ ```python
76
+ import nitlsconfig
77
+
78
+ # List configured services
79
+ clients = nitlsconfig.ClientConfig.list_services()
80
+ servers = nitlsconfig.ServerConfig.list_services()
81
+
82
+ if clients:
83
+ # Read one client configuration
84
+ client_info = nitlsconfig.ClientConfig(clients[0])
85
+ print(client_info.service_name)
86
+ print(client_info.certificate_mode)
87
+ print(client_info.certificate_chain_location.scheme)
88
+ print(client_info.certificate_chain_location.path)
89
+ print(client_info.certificate_chain_contents)
90
+
91
+ # Inspect target-specific configurations
92
+ for known_server in client_info.known_servers:
93
+ print(known_server.server_name)
94
+ print(known_server.server_mode)
95
+ print(known_server.trusted_certificates_location)
96
+
97
+ if servers:
98
+ # Read one server configuration
99
+ server_info = nitlsconfig.ServerConfig(servers[0])
100
+ print(server_info.service_name)
101
+ print(server_info.certificate_mode)
102
+ print(server_info.client_mode)
103
+ print(server_info.certificate_chain_location.scheme)
104
+ print(server_info.certificate_key_location.scheme)
105
+ print(server_info.trusted_certificates_location.scheme)
106
+ print(server_info.trusted_certificates_contents)
107
+
108
+ # Enumerate trusted certificates
109
+ for cert in server_info.trusted_certificates:
110
+ print(cert.display_name)
111
+ print(cert.trusted_certificate_location.path)
112
+ print(cert.trusted_certificate_contents)
113
+ ```
114
+
115
+
@@ -0,0 +1,116 @@
1
+ [project]
2
+ name = "nitlsconfig"
3
+ version = "1.0.0"
4
+ license = "MIT"
5
+ description = "Python API for reading nitlsconfig configurations and creating NI gRPC Device client channels from them"
6
+ authors = [{name = "NI", email = "opensource@ni.com"}]
7
+ maintainers = [
8
+ {name = "Philip Thong", email = "philip.thong@emerson.com"},
9
+ ]
10
+ readme = "README.md"
11
+ keywords = ["nitlsconfig", "tls", "mtls", "grpc", "configuration"]
12
+ classifiers = [
13
+ "Development Status :: 5 - Production/Stable",
14
+ "Intended Audience :: Developers",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Operating System :: Microsoft :: Windows",
17
+ "Operating System :: POSIX",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.9",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
25
+ ]
26
+ requires-python = ">=3.9"
27
+ dynamic = ["dependencies"]
28
+
29
+ # Reading NI TLS configuration is pure Python. Only nitlsconfig.grpc_channel
30
+ # needs grpcio, so the binary wheel is opt-in. pywin32 rides along with it
31
+ # because audit records are only produced when a channel is created, and the
32
+ # Windows Event Log logging handler cannot be written to without it.
33
+ [project.optional-dependencies]
34
+ grpc = ["grpcio>=1.49.0,<2.0", "pywin32>=306; sys_platform == 'win32'"]
35
+
36
+ [project.urls]
37
+ repository = "https://github.com/ni/nitlsconfig-python"
38
+ documentation = "https://nitlsconfig-python.readthedocs.io"
39
+
40
+ [project.scripts]
41
+ nitlsconfig-read = "nitlsconfig.cli:nitlsconfig_main"
42
+
43
+ [build-system]
44
+ requires = ["poetry-core>=1.9.0"]
45
+ build-backend = "poetry.core.masonry.api"
46
+
47
+ [tool.poetry]
48
+ packages = [{ include = "nitlsconfig", from = "src" }]
49
+ requires-poetry = '>=2.1,<3.0'
50
+
51
+ [tool.poetry.dependencies]
52
+ python = ">=3.9,<4.0"
53
+
54
+
55
+ [tool.poetry.group.lint.dependencies]
56
+ bandit = { version = ">=1.7", extras = ["toml"] }
57
+ ni-python-styleguide = ">=0.4.1"
58
+ mypy = ">=1.0"
59
+ pyright = { version = ">=1.1.400", extras = ["nodejs"] }
60
+
61
+ [tool.poetry.group.test.dependencies]
62
+ pytest = [
63
+ { version = ">=7.2", python = "<3.10" },
64
+ { version = ">=9.1.1", python = ">=3.10" },
65
+ ]
66
+ pytest-cov = ">=4.0"
67
+ pytest-mock = ">=3.0"
68
+ pytest-env = ">=1.0,<2.0"
69
+ cryptography = ">=41.0"
70
+
71
+ [tool.poetry.group.docs]
72
+ optional = true
73
+
74
+ [tool.poetry.group.docs.dependencies]
75
+ # The latest Sphinx requires a recent Python version.
76
+ Sphinx = [
77
+ { version = ">=8.1", python = ">=3.10,<3.11" },
78
+ { version = ">=8.2", python = "^3.11" },
79
+ ]
80
+ sphinx-rtd-theme = ">=1.0.0"
81
+ sphinx-autoapi = ">=1.8.4"
82
+ m2r2 = ">=0.3.2"
83
+ toml = ">=0.10.2"
84
+
85
+ [tool.pytest_env]
86
+ env_files = [".env"]
87
+
88
+ [tool.ni-python-styleguide]
89
+ extend_exclude = ".tox,docs"
90
+ application-import-names = "nitlsconfig,tests"
91
+
92
+ [tool.black]
93
+ extend-exclude = '\.tox/|docs/'
94
+ line-length = 100
95
+
96
+ [tool.mypy]
97
+ files = "src/nitlsconfig/,tests/"
98
+ namespace_packages = true
99
+ strict = true
100
+
101
+ [[tool.mypy.overrides]]
102
+ # grpcio does not ship a py.typed marker.
103
+ module = "grpc.*"
104
+ ignore_missing_imports = true
105
+
106
+ [tool.bandit]
107
+ skips = [
108
+ "B101", # assert_used
109
+ ]
110
+
111
+ [tool.pytest.ini_options]
112
+ addopts = "--doctest-modules --strict-markers"
113
+ testpaths = ["src/nitlsconfig", "tests"]
114
+
115
+ [tool.pyright]
116
+ include = ["src/", "tests/"]
@@ -0,0 +1,99 @@
1
+ """Python package to read settings from nitlsconfig and build NI gRPC Device channels from them.
2
+
3
+ The gRPC names below are resolved lazily: importing this package never imports
4
+ grpcio, so a caller that only reads NI TLS configuration does not pay for a
5
+ binary dependency it will not use. See the project README for install options.
6
+ """
7
+
8
+ from importlib.metadata import version
9
+ from importlib.util import find_spec
10
+ from typing import TYPE_CHECKING, Any
11
+
12
+ from nitlsconfig.audit import audit_session_connect
13
+ from nitlsconfig.cli import (
14
+ CertificateLocation,
15
+ ClientCertMode,
16
+ ClientConfig,
17
+ ClientServerMode,
18
+ LocationScheme,
19
+ ServerCertMode,
20
+ ServerClientMode,
21
+ ServerConfig,
22
+ TrustedCertificateData,
23
+ KnownServerData,
24
+ )
25
+ from nitlsconfig.errors import (
26
+ CommandFailedError,
27
+ CommandTimeoutError,
28
+ ExecutableNotFoundError,
29
+ InvalidOutputError,
30
+ NitlsconfigCliError,
31
+ NitlsconfigError,
32
+ TlsConfigurationError,
33
+ get_tls_connection_error_elaboration,
34
+ )
35
+
36
+ if TYPE_CHECKING:
37
+ # Imported eagerly for type checkers and editors, which do not run __getattr__.
38
+ from nitlsconfig.grpc_channel import (
39
+ RetryPolicy,
40
+ create_grpc_device_channel,
41
+ )
42
+
43
+ __version__ = version("nitlsconfig")
44
+
45
+ # Names re-exported from nitlsconfig.grpc_channel, which requires grpcio.
46
+ # A plain list literal, because pyright only tracks __all__ through a small set
47
+ # of literal forms; anything computed makes it give up on the export list.
48
+ _GRPC_EXPORTS = [
49
+ "RetryPolicy",
50
+ "create_grpc_device_channel",
51
+ ]
52
+
53
+ __all__ = [
54
+ "__version__",
55
+ "audit_session_connect",
56
+ "CertificateLocation",
57
+ "ClientCertMode",
58
+ "ClientConfig",
59
+ "ClientServerMode",
60
+ "LocationScheme",
61
+ "ServerCertMode",
62
+ "ServerClientMode",
63
+ "ServerConfig",
64
+ "NitlsconfigError",
65
+ "NitlsconfigCliError",
66
+ "ExecutableNotFoundError",
67
+ "CommandFailedError",
68
+ "CommandTimeoutError",
69
+ "InvalidOutputError",
70
+ "TlsConfigurationError",
71
+ "TrustedCertificateData",
72
+ "KnownServerData",
73
+ "get_tls_connection_error_elaboration",
74
+ ]
75
+
76
+ # The gRPC names are public API, but only on an install that can supply them.
77
+ # Listing them unconditionally would make `from nitlsconfig import *` raise
78
+ # ImportError without the grpc extra, since star-import resolves every name in
79
+ # __all__. find_spec only locates grpcio; it does not import it, so the lazy
80
+ # __getattr__ below still decides when grpcio is actually loaded.
81
+ if find_spec("grpc") is not None:
82
+ # pyright only tracks __all__ through inline literals, so it cannot follow
83
+ # this and warns that the export list may be incomplete. The TYPE_CHECKING
84
+ # block above already declares these names for static consumers.
85
+ __all__ += _GRPC_EXPORTS # pyright: ignore[reportUnsupportedDunderAll]
86
+
87
+
88
+ def __getattr__(name: str) -> Any:
89
+ """Resolve gRPC exports on first use, so importing this package does not need grpcio."""
90
+ if name in _GRPC_EXPORTS:
91
+ try:
92
+ from nitlsconfig import grpc_channel
93
+ except ImportError as exc: # pragma: no cover - requires an install without the extra
94
+ raise ImportError(
95
+ f"nitlsconfig.{name} requires grpcio, which is not installed. "
96
+ "Install it with: pip install nitlsconfig[grpc]"
97
+ ) from exc
98
+ return getattr(grpc_channel, name)
99
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,12 @@
1
+ """The NI TLS services this package builds transports for.
2
+
3
+ Only the NI gRPC Device Server is supported today. Anything else can still be
4
+ read through :class:`~nitlsconfig.cli.ClientConfig`, but has no channel factory.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ # The NI TLS registered service name for the NI gRPC Device Server: the file stem of
10
+ # ni-grpc-device.client.caps.yml, the Event Log source, and the record tag are all this
11
+ # one name, so records can be tied back to the configuration they describe.
12
+ SERVICE_NAME = "ni-grpc-device"