seclave-companion 1.1.2__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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Seclave AB
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,217 @@
1
+ Metadata-Version: 2.4
2
+ Name: seclave-companion
3
+ Version: 1.1.2
4
+ Summary: Desktop companion for the Seclave hardware password manager: browse, copy, and edit entries over USB
5
+ Author-email: seclave <code@seclave.se>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://www.seclave.se
8
+ Project-URL: Source, https://github.com/seclave/seclave-companion
9
+ Keywords: seclave,password-manager,hardware,usb,serial
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Environment :: X11 Applications
12
+ Classifier: Environment :: Win32 (MS Windows)
13
+ Classifier: Environment :: MacOS X
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Topic :: Security
18
+ Classifier: Topic :: Utilities
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Dynamic: license-file
23
+
24
+ # Seclave Companion
25
+
26
+ A desktop table view for a Seclave 2.0 hardware password manager, over the
27
+ device's USB-slave (CDC-ACM serial) protocol. It enumerates the entries stored
28
+ on the device into a searchable, sortable table and lets you copy a username or
29
+ password, add an entry, edit one, or delete one - each secret action confirmed
30
+ on the device's own screen.
31
+
32
+ It is one self-contained Python file using only the standard library: no pip
33
+ installs, no background service, and nothing written to disk. Secrets are read
34
+ from the device only when you ask for them, copied to the clipboard, and the
35
+ clipboard clears after 30 seconds and on exit.
36
+
37
+ The real security boundary is the Seclave itself - its display and joystick,
38
+ where you see and approve each action. This app is a convenience front-end.
39
+
40
+ ### Secrets in memory
41
+
42
+ Every host-side copy of a secret lives in mmap pages the app zeroes explicitly:
43
+ bytes are read from the serial port straight into an anonymous mmap arena (never
44
+ into an intermediate Python `bytes`), parsed in place, copied mmap-to-mmap into a
45
+ per-secret buffer, and the arena is wiped after every command. The two copies the
46
+ app cannot control are the kernel's tty receive buffer and the transient string
47
+ created at the moment a value is shown or placed on the clipboard (which the
48
+ clipboard and windowing system may then retain). The app does not lock pages into
49
+ RAM, and makes no claim of complete zeroization - the device's on-screen
50
+ confirmation, not host memory hygiene, is what actually protects your secrets.
51
+
52
+ ## Before you start
53
+
54
+ Put the device in USB-slave mode: on the Seclave, open the menu and select
55
+ **Usb slave**. The serial port only exists while the device is in that menu and
56
+ disappears when you leave it (or press UP). Launch the app, then click
57
+ **Load view**.
58
+
59
+ Labels and web passwords are loaded separately, on demand - one device
60
+ confirmation each. Loading the labels view confirms "Show all labels"; switching
61
+ the Group dropdown to **Web passwords (wwwfill)** the first time confirms "Show
62
+ all wwwfills". Each view is fetched only when you first show it, and switching
63
+ back to a view you already loaded this session is instant with no new prompt.
64
+
65
+ Access modes affect whether the device prompts you. In **Normal** (the default)
66
+ and **Ask all** modes, most reads pause on the device until you press the
67
+ joystick to confirm - the app shows a red "Look at your Seclave" alert bar
68
+ while it waits. In **Allow all** mode nothing prompts and reads return at once. Web
69
+ passwords (wwwfill) are read and written without a prompt in Normal mode; that
70
+ path is intentionally frictionless.
71
+
72
+ ## Running it
73
+
74
+ ### Any platform: pipx or uv
75
+
76
+ If you have pipx or uv (common on developer machines), this installs the
77
+ `seclave_companion` command on your PATH:
78
+
79
+ ```
80
+ pipx install seclave-companion # or: uv tool install seclave-companion
81
+ seclave_companion
82
+ ```
83
+
84
+ The Python running it must have Tk: python.org installers include it, uv's
85
+ managed Pythons include it, Homebrew needs `brew install python-tk`, and
86
+ Debian/Ubuntu needs `sudo apt install python3-tk`. On Linux you still need
87
+ serial access (see the packaged udev rule below); on macOS and Windows the
88
+ port works as-is.
89
+
90
+ ### Linux
91
+
92
+ The recommended way is the package (built by
93
+ `packaging/linux/build_linux_packages.sh`):
94
+
95
+ ```
96
+ sudo apt install ./seclave-companion_<version>_all.deb # Debian/Ubuntu
97
+ sudo dnf install ./seclave-companion-<version>.noarch.rpm # Fedora/RHEL
98
+ ```
99
+
100
+ It installs `seclave_companion` on your PATH, a desktop menu entry, and a udev
101
+ rule that keeps ModemManager off the port (it otherwise probes the new serial
102
+ device and can corrupt the first exchange), grants the logged-in user access
103
+ with no group setup, and creates a stable `/dev/seclave` symlink. Plug the
104
+ device in, put it in USB-slave mode, run `seclave_companion`.
105
+
106
+ To run from source instead, install Tk and start the file directly:
107
+
108
+ - Debian/Ubuntu: `sudo apt install python3-tk`
109
+ - Fedora: `sudo dnf install python3-tkinter`
110
+ - Arch: `sudo pacman -S tk`
111
+
112
+ ```
113
+ python3 seclave_companion.py
114
+ ```
115
+
116
+ Running from source you handle serial access yourself: add your user to the
117
+ `dialout` group, or install the packaged udev rule
118
+ (`packaging/linux/60-seclave.rules`) by hand.
119
+
120
+ ### Windows
121
+
122
+ Install Python 3 from python.org - it includes Tk. Then double-click the file or
123
+ run:
124
+
125
+ ```
126
+ py seclave_companion.py
127
+ ```
128
+
129
+ ### macOS
130
+
131
+ Install Python 3 from python.org - it bundles a working Tk 8.6. Apple's system
132
+ Python does not have a usable Tk. Then run:
133
+
134
+ ```
135
+ python3 seclave_companion.py
136
+ ```
137
+
138
+ ## What it does and does not do
139
+
140
+ - Reads the entry list, searches and sorts it, and switches to a web-passwords
141
+ view. Copies a username, password, or the Optional field (notes/domain) on
142
+ demand; fields read this way stay shown in the table. Show entry displays
143
+ every field of a row in a read-only window (password masked until you tick
144
+ "show"). Adds,
145
+ edits (as delete-then-add, with the dialog prefilled from the device), and
146
+ deletes entries. Generates passwords.
147
+ - It does not do bulk import or backup - those are better suited to the device's
148
+ faster mass-storage path and are handled by separate tooling.
149
+
150
+ ## Developer tooling
151
+
152
+ The `dev/` directory is not part of the shipped program. It lets you work
153
+ without hardware:
154
+
155
+ - `dev/stub_device.py` - a fake Seclave speaking the protocol over a
156
+ pseudo-terminal. Run it to get a port path, then point the app at it:
157
+
158
+ ```
159
+ python3 dev/stub_device.py # prints e.g. /dev/pts/7
160
+ python3 seclave_companion.py --port /dev/pts/7
161
+ ```
162
+
163
+ Options: `--delay SECONDS` simulates the confirmation pause; `--abort` makes
164
+ the device decline every confirmable command.
165
+
166
+ - `dev/test_protocol.py` - end-to-end tests of the protocol layer against the
167
+ stub: `python3 dev/test_protocol.py`.
168
+ - `dev/smoke_ui.py` - a headless check that the window loads, filters, and
169
+ copies a password: `xvfb-run -a python3 dev/smoke_ui.py` (or run it under any
170
+ display).
171
+
172
+ ## Releasing
173
+
174
+ **Bump `VERSION` in `seclave_companion.py` (near the top). That is the only
175
+ version written by hand.** Then commit, and tag the commit `v<version>`:
176
+
177
+ ```
178
+ git tag v1.2.0
179
+ git push origin v1.2.0
180
+ ```
181
+
182
+ Everything else derives from `VERSION`, so there is nothing else to keep in
183
+ step:
184
+
185
+ | Artifact | How it gets the version |
186
+ |---|---|
187
+ | PyPI sdist/wheel | `pyproject.toml` reads the `VERSION` attribute (`dynamic = ["version"]`) |
188
+ | `.deb` / `.rpm` | `build_linux_packages.sh` greps it and passes it to nfpm |
189
+ | Windows version resource | generated by `packaging/windows/make_version_info.py` |
190
+ | `SeclaveCompanion.exe` | PyInstaller stamps it from that resource |
191
+ | Installer + its filename | the Inno script reads `ProductVersion` back out of the packaged exe |
192
+ | Artifact filenames | the build scripts, from the same value |
193
+
194
+ The tag is the one stamp that cannot be derived - it is the input that starts
195
+ a release - so CI checks it against `VERSION` and fails the run if they
196
+ disagree. A `-rc.N` suffix is ignored by that check: `v1.2.0-rc.1` rehearses
197
+ the release of `1.2.0`, produces a draft prerelease, and deliberately skips
198
+ the PyPI upload so a rehearsal cannot burn the version (PyPI uploads are
199
+ immutable). Delete rehearsal tags and their draft releases afterwards.
200
+
201
+ Pushing the tag builds everything - deb, rpm, portable zip, one-file exe,
202
+ console exe, installer - on real Linux and Windows runners, attaches them with
203
+ `SHA256SUMS.txt` to a **draft** release, and publishes to PyPI on final tags.
204
+ The draft is yours to review, GPG-sign the checksums for, and publish. See
205
+ `.github/workflows/release.yml`.
206
+
207
+ To build locally without CI: `sh packaging/linux/build_linux_packages.sh`,
208
+ `powershell -File packaging\windows\build_windows.ps1` on Windows, or
209
+ `sh packaging/windows/build_on_wine.sh` to cross-build the Windows set on
210
+ Ubuntu. A Wine-built binary still has to be tested on real Windows before it
211
+ ships.
212
+
213
+ ## License
214
+
215
+ MIT - see the [LICENSE](LICENSE) file.
216
+
217
+ Seclave is a trademark of Seclave AB. This license grants no trademark rights.
@@ -0,0 +1,194 @@
1
+ # Seclave Companion
2
+
3
+ A desktop table view for a Seclave 2.0 hardware password manager, over the
4
+ device's USB-slave (CDC-ACM serial) protocol. It enumerates the entries stored
5
+ on the device into a searchable, sortable table and lets you copy a username or
6
+ password, add an entry, edit one, or delete one - each secret action confirmed
7
+ on the device's own screen.
8
+
9
+ It is one self-contained Python file using only the standard library: no pip
10
+ installs, no background service, and nothing written to disk. Secrets are read
11
+ from the device only when you ask for them, copied to the clipboard, and the
12
+ clipboard clears after 30 seconds and on exit.
13
+
14
+ The real security boundary is the Seclave itself - its display and joystick,
15
+ where you see and approve each action. This app is a convenience front-end.
16
+
17
+ ### Secrets in memory
18
+
19
+ Every host-side copy of a secret lives in mmap pages the app zeroes explicitly:
20
+ bytes are read from the serial port straight into an anonymous mmap arena (never
21
+ into an intermediate Python `bytes`), parsed in place, copied mmap-to-mmap into a
22
+ per-secret buffer, and the arena is wiped after every command. The two copies the
23
+ app cannot control are the kernel's tty receive buffer and the transient string
24
+ created at the moment a value is shown or placed on the clipboard (which the
25
+ clipboard and windowing system may then retain). The app does not lock pages into
26
+ RAM, and makes no claim of complete zeroization - the device's on-screen
27
+ confirmation, not host memory hygiene, is what actually protects your secrets.
28
+
29
+ ## Before you start
30
+
31
+ Put the device in USB-slave mode: on the Seclave, open the menu and select
32
+ **Usb slave**. The serial port only exists while the device is in that menu and
33
+ disappears when you leave it (or press UP). Launch the app, then click
34
+ **Load view**.
35
+
36
+ Labels and web passwords are loaded separately, on demand - one device
37
+ confirmation each. Loading the labels view confirms "Show all labels"; switching
38
+ the Group dropdown to **Web passwords (wwwfill)** the first time confirms "Show
39
+ all wwwfills". Each view is fetched only when you first show it, and switching
40
+ back to a view you already loaded this session is instant with no new prompt.
41
+
42
+ Access modes affect whether the device prompts you. In **Normal** (the default)
43
+ and **Ask all** modes, most reads pause on the device until you press the
44
+ joystick to confirm - the app shows a red "Look at your Seclave" alert bar
45
+ while it waits. In **Allow all** mode nothing prompts and reads return at once. Web
46
+ passwords (wwwfill) are read and written without a prompt in Normal mode; that
47
+ path is intentionally frictionless.
48
+
49
+ ## Running it
50
+
51
+ ### Any platform: pipx or uv
52
+
53
+ If you have pipx or uv (common on developer machines), this installs the
54
+ `seclave_companion` command on your PATH:
55
+
56
+ ```
57
+ pipx install seclave-companion # or: uv tool install seclave-companion
58
+ seclave_companion
59
+ ```
60
+
61
+ The Python running it must have Tk: python.org installers include it, uv's
62
+ managed Pythons include it, Homebrew needs `brew install python-tk`, and
63
+ Debian/Ubuntu needs `sudo apt install python3-tk`. On Linux you still need
64
+ serial access (see the packaged udev rule below); on macOS and Windows the
65
+ port works as-is.
66
+
67
+ ### Linux
68
+
69
+ The recommended way is the package (built by
70
+ `packaging/linux/build_linux_packages.sh`):
71
+
72
+ ```
73
+ sudo apt install ./seclave-companion_<version>_all.deb # Debian/Ubuntu
74
+ sudo dnf install ./seclave-companion-<version>.noarch.rpm # Fedora/RHEL
75
+ ```
76
+
77
+ It installs `seclave_companion` on your PATH, a desktop menu entry, and a udev
78
+ rule that keeps ModemManager off the port (it otherwise probes the new serial
79
+ device and can corrupt the first exchange), grants the logged-in user access
80
+ with no group setup, and creates a stable `/dev/seclave` symlink. Plug the
81
+ device in, put it in USB-slave mode, run `seclave_companion`.
82
+
83
+ To run from source instead, install Tk and start the file directly:
84
+
85
+ - Debian/Ubuntu: `sudo apt install python3-tk`
86
+ - Fedora: `sudo dnf install python3-tkinter`
87
+ - Arch: `sudo pacman -S tk`
88
+
89
+ ```
90
+ python3 seclave_companion.py
91
+ ```
92
+
93
+ Running from source you handle serial access yourself: add your user to the
94
+ `dialout` group, or install the packaged udev rule
95
+ (`packaging/linux/60-seclave.rules`) by hand.
96
+
97
+ ### Windows
98
+
99
+ Install Python 3 from python.org - it includes Tk. Then double-click the file or
100
+ run:
101
+
102
+ ```
103
+ py seclave_companion.py
104
+ ```
105
+
106
+ ### macOS
107
+
108
+ Install Python 3 from python.org - it bundles a working Tk 8.6. Apple's system
109
+ Python does not have a usable Tk. Then run:
110
+
111
+ ```
112
+ python3 seclave_companion.py
113
+ ```
114
+
115
+ ## What it does and does not do
116
+
117
+ - Reads the entry list, searches and sorts it, and switches to a web-passwords
118
+ view. Copies a username, password, or the Optional field (notes/domain) on
119
+ demand; fields read this way stay shown in the table. Show entry displays
120
+ every field of a row in a read-only window (password masked until you tick
121
+ "show"). Adds,
122
+ edits (as delete-then-add, with the dialog prefilled from the device), and
123
+ deletes entries. Generates passwords.
124
+ - It does not do bulk import or backup - those are better suited to the device's
125
+ faster mass-storage path and are handled by separate tooling.
126
+
127
+ ## Developer tooling
128
+
129
+ The `dev/` directory is not part of the shipped program. It lets you work
130
+ without hardware:
131
+
132
+ - `dev/stub_device.py` - a fake Seclave speaking the protocol over a
133
+ pseudo-terminal. Run it to get a port path, then point the app at it:
134
+
135
+ ```
136
+ python3 dev/stub_device.py # prints e.g. /dev/pts/7
137
+ python3 seclave_companion.py --port /dev/pts/7
138
+ ```
139
+
140
+ Options: `--delay SECONDS` simulates the confirmation pause; `--abort` makes
141
+ the device decline every confirmable command.
142
+
143
+ - `dev/test_protocol.py` - end-to-end tests of the protocol layer against the
144
+ stub: `python3 dev/test_protocol.py`.
145
+ - `dev/smoke_ui.py` - a headless check that the window loads, filters, and
146
+ copies a password: `xvfb-run -a python3 dev/smoke_ui.py` (or run it under any
147
+ display).
148
+
149
+ ## Releasing
150
+
151
+ **Bump `VERSION` in `seclave_companion.py` (near the top). That is the only
152
+ version written by hand.** Then commit, and tag the commit `v<version>`:
153
+
154
+ ```
155
+ git tag v1.2.0
156
+ git push origin v1.2.0
157
+ ```
158
+
159
+ Everything else derives from `VERSION`, so there is nothing else to keep in
160
+ step:
161
+
162
+ | Artifact | How it gets the version |
163
+ |---|---|
164
+ | PyPI sdist/wheel | `pyproject.toml` reads the `VERSION` attribute (`dynamic = ["version"]`) |
165
+ | `.deb` / `.rpm` | `build_linux_packages.sh` greps it and passes it to nfpm |
166
+ | Windows version resource | generated by `packaging/windows/make_version_info.py` |
167
+ | `SeclaveCompanion.exe` | PyInstaller stamps it from that resource |
168
+ | Installer + its filename | the Inno script reads `ProductVersion` back out of the packaged exe |
169
+ | Artifact filenames | the build scripts, from the same value |
170
+
171
+ The tag is the one stamp that cannot be derived - it is the input that starts
172
+ a release - so CI checks it against `VERSION` and fails the run if they
173
+ disagree. A `-rc.N` suffix is ignored by that check: `v1.2.0-rc.1` rehearses
174
+ the release of `1.2.0`, produces a draft prerelease, and deliberately skips
175
+ the PyPI upload so a rehearsal cannot burn the version (PyPI uploads are
176
+ immutable). Delete rehearsal tags and their draft releases afterwards.
177
+
178
+ Pushing the tag builds everything - deb, rpm, portable zip, one-file exe,
179
+ console exe, installer - on real Linux and Windows runners, attaches them with
180
+ `SHA256SUMS.txt` to a **draft** release, and publishes to PyPI on final tags.
181
+ The draft is yours to review, GPG-sign the checksums for, and publish. See
182
+ `.github/workflows/release.yml`.
183
+
184
+ To build locally without CI: `sh packaging/linux/build_linux_packages.sh`,
185
+ `powershell -File packaging\windows\build_windows.ps1` on Windows, or
186
+ `sh packaging/windows/build_on_wine.sh` to cross-build the Windows set on
187
+ Ubuntu. A Wine-built binary still has to be tested on real Windows before it
188
+ ships.
189
+
190
+ ## License
191
+
192
+ MIT - see the [LICENSE](LICENSE) file.
193
+
194
+ Seclave is a trademark of Seclave AB. This license grants no trademark rights.
@@ -0,0 +1,48 @@
1
+ # Packaging for PyPI: the app is one stdlib-only module, installed as the
2
+ # seclave_companion command. Version is read from VERSION in the module, so a
3
+ # release bump stays a one-line change.
4
+ #
5
+ # There are deliberately no dependencies. tkinter is standard library, but it
6
+ # is built against the Tcl/Tk C libraries and therefore ships with the
7
+ # interpreter or not at all - it cannot be expressed as a PyPI requirement,
8
+ # and packages on PyPI bearing its name are not official. The app checks for
9
+ # it at startup and prints the per-platform install command instead.
10
+
11
+ [build-system]
12
+ requires = ["setuptools>=77"]
13
+ build-backend = "setuptools.build_meta"
14
+
15
+ [project]
16
+ name = "seclave-companion"
17
+ dynamic = ["version"]
18
+ description = "Desktop companion for the Seclave hardware password manager: browse, copy, and edit entries over USB"
19
+ authors = [{name = "seclave", email = "code@seclave.se"}]
20
+ readme = "README.md"
21
+ license = "MIT"
22
+ license-files = ["LICENSE"]
23
+ requires-python = ">=3.9"
24
+ keywords = ["seclave", "password-manager", "hardware", "usb", "serial"]
25
+ classifiers = [
26
+ "Development Status :: 5 - Production/Stable",
27
+ "Environment :: X11 Applications",
28
+ "Environment :: Win32 (MS Windows)",
29
+ "Environment :: MacOS X",
30
+ "Intended Audience :: End Users/Desktop",
31
+ "Operating System :: OS Independent",
32
+ "Programming Language :: Python :: 3",
33
+ "Topic :: Security",
34
+ "Topic :: Utilities",
35
+ ]
36
+
37
+ [project.urls]
38
+ Homepage = "https://www.seclave.se"
39
+ Source = "https://github.com/seclave/seclave-companion"
40
+
41
+ [project.scripts]
42
+ seclave_companion = "seclave_companion:main"
43
+
44
+ [tool.setuptools]
45
+ py-modules = ["seclave_companion"]
46
+
47
+ [tool.setuptools.dynamic]
48
+ version = {attr = "seclave_companion.VERSION"}