Skip to content
Open
Show file tree
Hide file tree
Changes from 83 commits
Commits
Show all changes
171 commits
Select commit Hold shift + click to select a range
98adf81
feat(fido2): add FIDO2 application implementation
DennisDyallo Jan 27, 2026
61139b9
feat(piv): add PIV application implementation
DennisDyallo Jan 27, 2026
0b740e1
feat(piv-example): add PivTool CLI example application
DennisDyallo Jan 27, 2026
9666705
fix(piv-example): fix 5 e2e bugs found during autonomous API coverage…
DennisDyallo Apr 1, 2026
4ed7c2a
fix(piv-example): add missing newlines at end of files
DennisDyallo Apr 1, 2026
2e8d3b4
feat(piv): add session-layer DecryptAsync modelled after Python yubik…
DennisDyallo Apr 1, 2026
66e33a9
test(piv): add integration tests for DecryptAsync session-layer unpad…
DennisDyallo Apr 1, 2026
9002deb
Merge remote-tracking branch 'origin/yubikit-fido' into yubikit-fido2…
DennisDyallo Apr 1, 2026
e318c6c
feat(oath): add OATH applet implementation
DennisDyallo Apr 1, 2026
1a30c18
feat(yubiotp): add YubiOTP applet implementation
DennisDyallo Apr 1, 2026
16d71ac
feat(hsmauth): add YubiHSM Auth applet implementation
DennisDyallo Apr 1, 2026
c39cce0
feat(openpgp): add OpenPGP applet implementation
DennisDyallo Apr 1, 2026
bb5ecf7
feat(fido2): add FidoTool CLI example application
DennisDyallo Apr 1, 2026
f3ae48e
Merge branch 'yubikit-yubiotp' into yubikit-applets
DennisDyallo Apr 1, 2026
ef57ce8
Merge branch 'yubikit-hsmauth' into yubikit-applets
DennisDyallo Apr 1, 2026
58161bc
Merge branch 'yubikit-openpgp' into yubikit-applets
DennisDyallo Apr 1, 2026
1d46c2f
Merge branch 'yubikit-fido2-cli' into yubikit-applets
DennisDyallo Apr 1, 2026
0ce2a34
fix: exclude FIDO2 integration tests from solution
DennisDyallo Apr 1, 2026
b6c1a5f
fix(oath): address coding standard violations
DennisDyallo Apr 1, 2026
0513512
fix(openpgp): address coding standard violations
DennisDyallo Apr 1, 2026
c53719d
fix(hsmauth): address security and coding standard violations
DennisDyallo Apr 1, 2026
677d21f
fix(fido2): rewrite integration tests to use standard WithYubiKey inf…
DennisDyallo Apr 1, 2026
c89208d
fix(yubiotp): address coding standard violations
DennisDyallo Apr 1, 2026
bbd7fc0
refactor(oath): rewrite CLI to match ykman command structure
DennisDyallo Apr 1, 2026
ee645c9
refactor(fido2): rewrite CLI to match ykman command structure
DennisDyallo Apr 1, 2026
03df1b9
refactor(oath): rewrite CLI to match ykman command structure
DennisDyallo Apr 1, 2026
236ce99
refactor(yubiotp): rewrite CLI to match ykman command structure
DennisDyallo Apr 1, 2026
aca6ad8
refactor(openpgp): rewrite CLI to match ykman command structure
DennisDyallo Apr 1, 2026
ff1b32b
refactor(hsmauth): rewrite CLI to match ykman command structure
DennisDyallo Apr 1, 2026
bc23cc6
fix(yubiotp): fix multi-transport device selection in OtpTool
DennisDyallo Apr 1, 2026
f831b14
fix(fido2): auto-select HID FIDO transport in non-interactive CLI mode
DennisDyallo Apr 2, 2026
38fcb75
fix(core): treat firmware major version 0 as sentinel for alpha/beta …
DennisDyallo Apr 2, 2026
251b746
fix(oath): fix credential ID parsing in CalculateAllAsync
DennisDyallo Apr 2, 2026
856fd84
refactor(oath,hsmauth): normalize DeviceSelector to canonical non-int…
DennisDyallo Apr 2, 2026
66726aa
refactor(yubiotp,openpgp): normalize DeviceSelector to canonical non-…
DennisDyallo Apr 2, 2026
e76811f
fix(oath): fix static CancellationTokenSource causing inter-test canc…
DennisDyallo Apr 2, 2026
9ebc34f
fix(hsmauth): fix integration test failures and wire protocol bugs
DennisDyallo Apr 2, 2026
7dc0991
fix(core,openpgp): fix APDU configuration and test transport filter f…
DennisDyallo Apr 2, 2026
11de30e
docs: add implementation plans and GOAL.md files for agate orchestration
DennisDyallo Apr 2, 2026
8fa0707
docs: add future work items to plan
DennisDyallo Apr 2, 2026
4112711
fix(openpgp): fix 6 bugs found during integration testing
DennisDyallo Apr 2, 2026
78fd8e3
docs: document OpenPGP AttestKey alpha firmware gap in future work
DennisDyallo Apr 2, 2026
43b7328
docs: add final state document for yubikit-applets branch
DennisDyallo Apr 2, 2026
40553ae
docs: add FIDO2 user-presence validation instructions
DennisDyallo Apr 2, 2026
e8b4a73
feat(fido2): add set-pin CLI command for fresh device PIN enrollment
DennisDyallo Apr 2, 2026
4418333
docs: add FIDO2 validation results to final state
DennisDyallo Apr 2, 2026
5b599f5
fix(yubiotp): fix 3 bugs found during integration testing on alpha fi…
DennisDyallo Apr 2, 2026
9931a0a
fix(tests): add AllowUnknownSerials and pin YubiOTP tests to SmartCard
DennisDyallo Apr 2, 2026
364c8ae
docs: update final state — YubiOTP tests done, AllowUnknownSerials do…
DennisDyallo Apr 2, 2026
b80e09e
docs: add CLI shared infrastructure extraction plan (#12)
DennisDyallo Apr 2, 2026
32733e3
feat(cli): extract shared CLI infrastructure into Yubico.YubiKit.Cli.…
DennisDyallo Apr 2, 2026
e854036
docs: update plans and add handoff document
DennisDyallo Apr 2, 2026
c304038
merge: integrate yubikit-piv branch into yubikit-applets
DennisDyallo Apr 2, 2026
60d2111
fix(tests): auto-tag WithYubiKey tests and make build.cs unit-only by…
DennisDyallo Apr 2, 2026
24f1c4b
refactor(build): DRY helpers, fix GetArgument and FilterBullseyeArgs …
DennisDyallo Apr 2, 2026
904712b
refactor: restructure project folders under src/ with stripped prefixes
DennisDyallo Apr 2, 2026
eac64db
fix(tests): correct 8 pre-existing unit test failures across Core, Fi…
DennisDyallo Apr 2, 2026
bbcd2dd
feat(cli): extract InteractiveMenuBuilder and SessionHelper into Cli.…
DennisDyallo Apr 2, 2026
8801c83
fix(tests): use invalid key length in PinUvAuthProtocolV2 test
DennisDyallo Apr 2, 2026
ce945ad
docs: update handoff document for session end
DennisDyallo Apr 2, 2026
f648e03
fix(cli): use firmware-dependent touch timing in FidoTool reset
DennisDyallo Apr 2, 2026
b6f5ed0
chore(build): remove clean from restore dependency chain
DennisDyallo Apr 2, 2026
3106fff
fix(otp,oath): align flag values and defaults with ykman canonical
DennisDyallo Apr 2, 2026
bd97961
fix(build): use incremental builds and add xUnit v3 MTP filter transl…
DennisDyallo Apr 2, 2026
c303277
docs: update handoff document for session end
DennisDyallo Apr 2, 2026
358ed29
docs: update handoff document with ykman fixes and build.cs changes
DennisDyallo Apr 2, 2026
e022e78
style: codebase consistency pass — null checks, regions, timing fixes
DennisDyallo Apr 2, 2026
fbf335d
feat(build): add --smoke flag, DRY helpers, and integration test docs
DennisDyallo Apr 2, 2026
37c251e
style: modernize collection initialization to collection expressions
DennisDyallo Apr 2, 2026
2971a75
fix: remove dead CtapException stub from Core
DennisDyallo Apr 2, 2026
f47adbd
fix(openpgp): correct inverted P2 mapping in VerifyPinAsync
DennisDyallo Apr 2, 2026
99186fb
perf: remove unnecessary .ToArray() allocations on net10
DennisDyallo Apr 2, 2026
e817d3c
fix(openpgp): fix AttestKey response handling and certificate slot index
DennisDyallo Apr 2, 2026
f31cc7d
Merge branch 'style/codebase-consistency-pass' into yubikit-applets
DennisDyallo Apr 2, 2026
66b9a75
fix: use IsSupported() for firmware feature checks on alpha devices
DennisDyallo Apr 2, 2026
addf582
fix(otp): use HidOtp for HMAC-SHA1 challenge-response test
DennisDyallo Apr 2, 2026
23d610d
fix(piv): bypass .NET TripleDES weak key rejection for PIV management…
DennisDyallo Apr 2, 2026
82f8451
fix(core,openpgp,hsmauth): fix TLV parsing, algorithm info fallback, …
DennisDyallo Apr 2, 2026
1017309
ci: install pcscd and fix NuGet cache key for Linux CI
DennisDyallo Apr 2, 2026
738123a
ci,fix,chore: fix Linux CI pcscd setup, SDK graceful degradation, Nat…
DennisDyallo Apr 2, 2026
dd6ba87
docs: update handoff document for session end
DennisDyallo Apr 2, 2026
cab0c29
ci: tighten pcscd socket wait and use chmod 666 (Opus expert review)
DennisDyallo Apr 2, 2026
8dd1043
ci,fix: install libudev-dev and handle missing udev on Linux for HID …
DennisDyallo Apr 2, 2026
e58b611
security(core,fido2,piv): fix sensitive data handling across SCP, PIN…
DennisDyallo Apr 3, 2026
20d31cc
fix(fido2,openpgp,hsmauth,otp,core): fix SDK bugs discovered during i…
DennisDyallo Apr 8, 2026
f32ef63
test: add 30 integration tests covering 60 of 75 identified SDK gaps
DennisDyallo Apr 8, 2026
8bee286
fix(fido2/tests): replace reset hook with known-PIN normalization
DennisDyallo Apr 8, 2026
3c11350
fix(fido2/tests): align FidoTestData.Pin with KnownTestPinString
DennisDyallo Apr 8, 2026
966d701
fix(fido2/tests): mark ForceChangePin as RequiresUserPresence, clean …
DennisDyallo Apr 8, 2026
5511c10
docs: update handoff — FIDO2 fully verified, all 8 modules green
DennisDyallo Apr 8, 2026
c74570e
fix(cli): fix 4 bugs across PivTool, FidoTool, HsmAuthTool, Managemen…
DennisDyallo Apr 8, 2026
64b0311
feat(cli): add unified yk CLI with all 7 YubiKey applets
DennisDyallo Apr 8, 2026
47b0136
fix(cli): wire --force flag on management reset, stage all yk CLI files
DennisDyallo Apr 8, 2026
a9eaa04
docs: update progress file with E2E results and refresh handoff
DennisDyallo Apr 8, 2026
d175b78
fix(cli): map CTAP bio errors to structured exit codes
DennisDyallo Apr 8, 2026
6af5033
docs: update handoff and progress — CTAP exit codes resolved
DennisDyallo Apr 9, 2026
37e9568
Update src/Core/src/SmartCard/Scp/ScpState.cs
DennisDyallo Apr 9, 2026
f749f2a
Update src/Core/src/SmartCard/Scp/ScpState.Scp03.cs
DennisDyallo Apr 9, 2026
15396c8
security(core,fido2,piv): zero sensitive buffers and fix data leak pa…
DennisDyallo Apr 9, 2026
24a0470
security(core,oath,piv,fido2): fix buffer lifecycle and disposal patt…
DennisDyallo Apr 9, 2026
75353fd
security(fido2,openpgp,oath): replace string PIN/password APIs with R…
DennisDyallo Apr 9, 2026
3131dc7
security(cli): migrate CLI tools to ConsoleCredentialReader for PIN/p…
DennisDyallo Apr 9, 2026
b810749
refactor(credentials): move module-specific CredentialReaderOptions t…
DennisDyallo Apr 9, 2026
2d6f2b4
security: address Copilot review findings from PR #447
DennisDyallo Apr 9, 2026
efe0753
security(piv): remove .Memory.Span.ToArray() PIN/key copies in PivToo…
DennisDyallo Apr 9, 2026
b623178
security(openpgp): add IDisposable to Kdf to zero salt/hash material
DennisDyallo Apr 9, 2026
c244013
security: add grep-based security taxonomy audit script
DennisDyallo Apr 9, 2026
d04a49e
chore(skills): add workflow-security-audit skill
DennisDyallo Apr 9, 2026
41e013b
security: expand taxonomy to T12 with T10/T11/T12 from Copilot round-3
DennisDyallo Apr 9, 2026
8de98b4
security(scp): dispose ScpProcessor on auth failure, zero encrypted c…
DennisDyallo Apr 9, 2026
d121b71
security(fido2): fix T12 ownership violation in CredentialManagement.…
DennisDyallo Apr 9, 2026
e0b74f0
security: fix preparedData zeroing, add ownership docs, acknowledge b…
DennisDyallo Apr 9, 2026
e1316c7
chore: update handoff for session close — all security fixes complete
DennisDyallo Apr 9, 2026
c0429bb
security(core): convert ApduCommand from readonly record struct to se…
DennisDyallo Apr 9, 2026
51c7de8
security(core,piv): fix 7 issues from Copilot review round 3
DennisDyallo Apr 9, 2026
4f400f4
chore: update handoff — round 3 Copilot fixes complete, awaiting re-r…
DennisDyallo Apr 9, 2026
0b6938a
security(openpgp): fix Kdf buffer ownership — always clone on init
DennisDyallo Apr 10, 2026
248e7a5
tests: add cancellation token support
DennisDyallo Apr 10, 2026
331e048
misc: add ConfigureAwait(false) to async calls
DennisDyallo Apr 10, 2026
3a4f921
refactor(core): ApduCommand → readonly record struct with passthrough…
DennisDyallo Apr 10, 2026
d9901d5
docs: update CLAUDE.md for ApduCommand readonly record struct refactor
DennisDyallo Apr 10, 2026
59b629e
merge: integrate security remediation into yubikit-applets
DennisDyallo Apr 10, 2026
956bf19
docs: refresh handoff — post-merge state, security remediation complete
DennisDyallo Apr 10, 2026
7166b33
refactor(cli): migrate commands to Cli.Commands shared library
DennisDyallo Apr 10, 2026
4f73fc7
refactor(cli): remove migrated files from YkTool
DennisDyallo Apr 10, 2026
de8437d
fix(management-tests): restrict SCP and performance tests to SmartCar…
DennisDyallo Apr 10, 2026
244943d
fix(yubiopt): increase HID OTP timeout and fix test transport constra…
DennisDyallo Apr 10, 2026
b4e5f7c
fix(piv): TLV encoding bug, buffer zeroing, connection leak, dead code
DennisDyallo Apr 15, 2026
3c38d28
fix(fido2): SHA256 API, auth tag zeroing, DisposeAsync, dead code
DennisDyallo Apr 15, 2026
9ddb021
fix(oath): zero APDU secret buffer, GeneratedRegex, culture-safe parsing
DennisDyallo Apr 15, 2026
70bdf5b
fix(yubiotp): connection leak, NDEF truncation validation, cleanup
DennisDyallo Apr 15, 2026
39a04ec
fix(openpgp): DER P-521 encoding, key zeroing, pin truncation guard
DennisDyallo Apr 15, 2026
cc5303c
fix(secdomain): swapped checksum args, key zeroing, resource leaks, d…
DennisDyallo Apr 15, 2026
bca1819
fix(yubihsm): PublicKeyLength off-by-one, wrong error handler, mutabl…
DennisDyallo Apr 15, 2026
adae46d
refactor(piv): extract EnsureProtocol guard, merge crypto/parser methods
DennisDyallo Apr 15, 2026
a3fd770
refactor(fido2): fix ExtensionOutput.Decode, extract CoseKeyWriter, d…
DennisDyallo Apr 15, 2026
ae0b269
refactor(oath): immutable Credential.Id, TLV concat helper, ArrayBuff…
DennisDyallo Apr 15, 2026
f2c0781
refactor(yubiotp): extract HMAC key processing, constructor validatio…
DennisDyallo Apr 15, 2026
8a5f0fe
refactor(openpgp): fix X25519 slot bug, consolidate KeyRef switches, …
DennisDyallo Apr 15, 2026
ce2ce5b
refactor(secdomain): expand interface, extract PutEcKey helper, Membe…
DennisDyallo Apr 15, 2026
9c84190
refactor(yubihsm): extract retry handler, transmit pattern, immutable…
DennisDyallo Apr 15, 2026
25ad4b8
feat(core): add BerLength utility, ExtractRetryCount, EnsureReady
DennisDyallo Apr 15, 2026
d5a3db4
fix: connection leak in 6 modules' CreateSessionAsync methods
DennisDyallo Apr 15, 2026
ade7d8a
refactor: use Core BerLength and ExtractRetryCount utilities
DennisDyallo Apr 15, 2026
f8a0339
fix(core): remove unused EnsureReady from ApplicationSession
DennisDyallo Apr 15, 2026
81ea261
fix(piv): DES zeroing, BER lengths, retry extraction, ArrayBufferWriter
DennisDyallo Apr 15, 2026
892a2d5
fix(fido2): LargeBlob CBOR parse bug, extract Encapsulate ECDH helper
DennisDyallo Apr 15, 2026
c0acfeb
fix(oath): CredentialData IDisposable, ValidateAsync/SetKeyAsync API …
DennisDyallo Apr 15, 2026
380bef0
fix(yubiotp): strict access code validation, cancellation exception f…
DennisDyallo Apr 15, 2026
3b5f280
fix(openpgp): hash zeroing, Kdf disposal chain, BerLength for ASN.1 I…
DennisDyallo Apr 15, 2026
b996c6e
fix(secdomain): Tlv disposal, bounds check, remove caller key mutatio…
DennisDyallo Apr 15, 2026
a2edc0c
feat(core): add TlvHelper.EncodeAndDisposeList for safe Tlv lifecycle
DennisDyallo Apr 15, 2026
b74c0dc
fix(yubihsm): dispose Tlv objects via EncodeAndDisposeList (10 sites)
DennisDyallo Apr 15, 2026
d6113c8
fix(piv): dispose Tlv objects in parse methods (5 sites)
DennisDyallo Apr 15, 2026
1af1581
Merge branch 'yubikey-codeaudit' of github.com:Yubico/Yubico.NET.SDK …
DennisDyallo Apr 15, 2026
52d9450
refactor(piv): split CryptoBlock into EncryptBlock/DecryptBlock with …
DennisDyallo Apr 15, 2026
fb216d3
docs: add TODO backlog work plan, stage 4 plan, update handoff
DennisDyallo Apr 15, 2026
9421ddb
Merge branch 'yubikey-codeaudit' of github.com:Yubico/Yubico.NET.SDK …
DennisDyallo Apr 15, 2026
24db19c
fix(piv): clone ModPow result before zeroing BigInteger allocation
DennisDyallo Apr 15, 2026
01e4b99
test(fido2): standardize RequiresUserPresence trait to TestCategories…
DennisDyallo Apr 15, 2026
c4c591b
fix(core,fido2): HID DeviceId collision and CTAP2.0 PIN token fallback
DennisDyallo Apr 15, 2026
16c0c27
fix(fido2): ChangePin test uses KnownTestPin instead of hardcoded PIN
DennisDyallo Apr 16, 2026
34171ea
test(fido2): fix AuthenticatorConfig tests for idempotent, self-heali…
DennisDyallo Apr 16, 2026
3b76ca2
refactor(oath): replace ConcatTlvs with collection spread and add Zer…
DennisDyallo Apr 16, 2026
150133d
Merge pull request #455 from Yubico/yubikey-codeaudit
DennisDyallo Apr 18, 2026
3fcf5a4
test(fido2): fix unit tests broken by production code updates
DennisDyallo Apr 20, 2026
8325527
ci: publish 2.0 preview packages to GitHub Packages on push
DennisDyallo Apr 20, 2026
2aa9c06
ci: upgrade GitHub Actions to v5 (Node.js 24)
DennisDyallo Apr 20, 2026
e48dbd6
test(core): fix xUnit1031 and xUnit2031 analyzer warnings
DennisDyallo Apr 20, 2026
594dd84
chore: rename build.cs → toolchain.cs and add publish-remote target
DennisDyallo Apr 20, 2026
b76b614
refactor(toolchain): fix all CodeAudit findings and harden secret han…
DennisDyallo Apr 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
15 changes: 14 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,23 @@ jobs:
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props') }}
restore-keys: |
${{ runner.os }}-nuget-

- name: Install PC/SC dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends pcscd libpcsclite-dev libudev-dev
# Run pcscd directly (bypasses systemd/socket-activation issues on CI runners)
# and open socket permissions so the test runner user can connect
sudo mkdir -p /run/pcscd
sudo pcscd --foreground &
# Wait for socket to appear (more robust than fixed sleep)
timeout 10 bash -c 'until [ -S /run/pcscd/pcscd.comm ]; do sleep 0.2; done' || true
# Open socket read/write for the runner user (sockets don't need +x)
sudo chmod 666 /run/pcscd/pcscd.comm || true

- name: Build
run: dotnet build.cs build

Expand Down
33 changes: 23 additions & 10 deletions BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ dotnet build.cs -- build --project Piv --clean

### Available Targets

- **clean** - Remove artifacts directory (and optionally run `dotnet clean`)
- **restore** - Restore NuGet dependencies (depends on: clean)
- **build** - Build the solution (depends on: clean, restore)
- **test** - Run unit tests with nice summary output (depends on: clean, restore, build)
- **coverage** - Run tests with code coverage collection (depends on: clean, restore, build)
- **pack** - Create NuGet packages (depends on: clean, restore, build)
- **clean** - Remove artifacts directory (and optionally run `dotnet clean`); must be specified explicitly
- **restore** - Restore NuGet dependencies
- **build** - Build the solution (depends on: restore)
- **test** - Run unit tests with nice summary output (depends on: restore, build)
- **coverage** - Run tests with code coverage collection (depends on: restore, build)
- **pack** - Create NuGet packages (depends on: restore, build)
- **setup-feed** - Configure local NuGet feed
- **publish** - Publish packages to local feed (depends on: pack, setup-feed)
- **default** - Run tests and publish (depends on: test, publish)
Expand All @@ -55,6 +55,8 @@ dotnet build.cs -- build --project Piv --clean
- `--clean` - Run `dotnet clean` before build
- `--filter <expression>` - Test filter expression (e.g., `"FullyQualifiedName~MyTest"`)
- `--project <name>` - Build/test specific project only (partial match, e.g., `Piv`)
- `--integration` - Include integration tests (requires `--project`)
- `--smoke` - Smoke test mode: skip `Slow` and `RequiresUserPresence` tests (fast integration runs)
- `-h, --help` - Show help message (use `dotnet build.cs -- --help`)

### Examples
Expand All @@ -78,17 +80,23 @@ dotnet build.cs test
# Run tests for specific project with filter
dotnet build.cs test --project Piv --filter "Method~Sign"

# Run tests with code coverage
# Run tests with code coverage (xUnit v2 unit test projects only)
dotnet build.cs coverage

# Run integration tests for a specific module
dotnet build.cs test --integration --project Piv

# Quick smoke test (skips slow RSA keygen and user-presence tests)
dotnet build.cs -- test --integration --project Piv --smoke

# Create and publish packages with custom version
dotnet build.cs publish --package-version 1.0.0-preview.2

# Dry run to see what would be published
dotnet build.cs publish --dry-run

# Full clean build
dotnet build.cs build --clean
# Full clean build (delete artifacts, then build)
dotnet build.cs clean build
```

## Target Dependencies
Expand All @@ -98,11 +106,12 @@ default
├── test
│ └── build
│ └── restore
│ └── clean
└── publish
├── pack
│ └── build (shared)
└── setup-feed

clean (standalone — must be specified explicitly)
```

## Output
Expand All @@ -125,6 +134,10 @@ The build script automatically discovers projects using glob patterns:

This means you don't need to manually update the build script when adding new projects that follow the standard structure. Run `dotnet build.cs -- --help` to see the current list of discovered projects.

## Code Coverage

The `coverage` target collects coverage via `dotnet test` with the `coverlet` collector. Both xUnit v2 and v3 (MTP) projects are supported via the VSTest compatibility layer. Use `--project` to run coverage for a specific module.

## xUnit v2 vs v3 Test Runner Detection

**IMPORTANT: Always use `dotnet build.cs test` instead of invoking `dotnet test` directly.**
Expand Down
46 changes: 33 additions & 13 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This file provides guidance to AI agents when working with code in this repository.

**IMPORTANT:** If you are working in a subproject directory (e.g., `Yubico.YubiKit.SecurityDomain/`, `Yubico.YubiKit.Piv/`, etc.), you MUST also read that subproject's `CLAUDE.md` file if it exists. Subproject CLAUDE.md files contain specific patterns, test harness details, and context for that module.
**IMPORTANT:** If you are working in a subproject directory (e.g., `src/SecurityDomain/`, `src/Piv/`, etc.), you MUST also read that subproject's `CLAUDE.md` file if it exists. Subproject CLAUDE.md files contain specific patterns, test harness details, and context for that module.

## Project Overview

Expand All @@ -17,24 +17,29 @@ Yubico.NET.SDK (YubiKit) is a .NET SDK for interacting with YubiKey devices. The

The SDK is organized into the following modules:

All project folders live under `src/` with the `Yubico.YubiKit.` prefix stripped from directory names. Assembly names, namespaces, and DLL output names remain unchanged (e.g., `Yubico.YubiKit.Core`).

**Core Infrastructure:**
- `Yubico.YubiKit.Core/` - Device management, connection abstractions, APDU protocol handling, platform interop
- `Yubico.YubiKit.Management/` - Device information queries, capability detection, firmware version
- `src/Core/` - Device management, connection abstractions, APDU protocol handling, platform interop
- `src/Management/` - Device information queries, capability detection, firmware version

**YubiKey Applications:**
- `Yubico.YubiKit.Piv/` - PIV (Personal Identity Verification) smart card functionality
- `Yubico.YubiKit.Fido2/` - FIDO2/WebAuthn authentication
- `Yubico.YubiKit.Oath/` - TOTP/HOTP one-time password generation
- `Yubico.YubiKit.YubiOtp/` - Yubico OTP configuration and generation
- `Yubico.YubiKit.OpenPgp/` - OpenPGP card implementation
- `Yubico.YubiKit.SecurityDomain/` - Secure Channel Protocol (SCP03), key management
- `src/Piv/` - PIV (Personal Identity Verification) smart card functionality
- `src/Fido2/` - FIDO2/WebAuthn authentication
- `src/Oath/` - TOTP/HOTP one-time password generation
- `src/YubiOtp/` - Yubico OTP configuration and generation
- `src/OpenPgp/` - OpenPGP card implementation
- `src/SecurityDomain/` - Secure Channel Protocol (SCP03), key management

**Hardware Security Modules:**
- `Yubico.YubiKit.YubiHsm/` - YubiHSM 2 hardware security module integration
- `src/YubiHsm/` - YubiHSM 2 hardware security module integration

**Shared Infrastructure:**
- `src/Cli.Shared/` - Shared CLI infrastructure for example tools

**Testing Infrastructure:**
- `Yubico.YubiKit.Tests.Shared/` - Shared test utilities, multi-transport test harness
- `Yubico.YubiKit.Tests.TestProject/` - xUnit v3 test project structure
- `src/Tests.Shared/` - Shared test utilities, multi-transport test harness
- `src/Tests.TestProject/` - xUnit v3 test project structure

**Module-Specific Documentation:**
Each module directory may contain:
Expand Down Expand Up @@ -177,7 +182,7 @@ dotnet build Yubico.YubiKit.sln
dotnet test Yubico.YubiKit.sln

# Run specific test project
dotnet test Yubico.YubiKit.Core/tests/Yubico.YubiKit.Core.UnitTests/Yubico.YubiKit.Core.UnitTests.csproj
dotnet test src/Core/tests/Yubico.YubiKit.Core.UnitTests/Yubico.YubiKit.Core.UnitTests.csproj

# Run with coverage directly
dotnet test --settings coverlet.runsettings.xml --collect:"XPlat Code Coverage"
Expand Down Expand Up @@ -1141,6 +1146,21 @@ bool isValid = expected.SequenceEqual(actual);

## Testing

### Integration Test Strategy

**Run only what's affected.** Don't run the full integration suite unless you're finishing a module or touching shared infrastructure.

| Phase | What to run | Command |
|-------|------------|---------|
| **During development** | Smoke test on affected module only | `dotnet build.cs -- test --integration --project Piv --smoke` |
| **Targeted check** | Specific test you touched | `dotnet build.cs -- test --integration --project Oath --filter "FullyQualifiedName~Calculate"` |
| **Finishing a module** | Full integration for that module | `dotnet build.cs -- test --integration --project Piv` |
| **Before PR** | Full integration for all affected modules | Run per-module, not all modules |

**`--smoke` skips:** `Slow` tests (RSA 3072/4096 keygen, 30+ sec each) and `RequiresUserPresence` tests (need physical touch).

**Mark slow tests:** Any integration test that generates RSA 3072+ keys or has delays >5s must have `[Trait(TestCategories.Category, TestCategories.Slow)]`.

### Test Philosophy: Value Over Coverage

**CRITICAL: Only write tests that provide real value. Don't create tests just to increase coverage metrics.**
Expand Down
3 changes: 2 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<!-- Third-party Dependencies -->
<PackageVersion Include="System.Formats.Cbor" Version="10.0.2" />
<PackageVersion Include="System.Reactive" Version="6.0.1" />
<PackageVersion Include="Yubico.NativeShims" Version="1.14.0" />
<PackageVersion Include="Yubico.NativeShims" Version="1.16.0" />
<!-- Test Dependencies -->
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.v3" Version="3.0.0" />
Expand All @@ -37,6 +37,7 @@
<PackageVersion Include="Xunit.SkippableFact" Version="1.5.23" />
<!-- CLI / Console Tools -->
<PackageVersion Include="Spectre.Console" Version="0.49.1" />
<PackageVersion Include="Spectre.Console.Cli" Version="0.49.1" />
<!-- Build Tools -->
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0" />
Expand Down
119 changes: 119 additions & 0 deletions Plans/cli-shared-infrastructure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# CLI Shared Infrastructure Extraction — Plan (#12)

**Status:** Review complete, ready for implementation
**Branch:** `yubikit-applets` (future work)
**Created:** 2026-04-02

---

## Problem

All 5 CLIs (ManagementTool, OathTool, FidoTool, OpenPgpTool, HsmAuthTool) share ~2600 LOC of duplicated patterns. No shared project exists — each CLI copy-pastes device selection, output formatting, argument parsing, and lifecycle management.

## Proposed Solution

New project: `Yubico.YubiKit.Cli.Shared`

```
Yubico.YubiKit.Cli.Shared/
├── src/
│ ├── Device/
│ │ ├── DeviceSelection.cs (shared record)
│ │ ├── DeviceSelectorBase.cs (abstract base, ~200 LOC)
│ │ ├── FormFactorFormatter.cs
│ │ └── ConnectionTypeFormatter.cs
│ ├── Output/
│ │ ├── OutputHelpers.cs (Spectre.Console variant)
│ │ ├── PlainTextOutputHelpers.cs (pipe-friendly alternative)
│ │ ├── ConfirmationPrompts.cs
│ │ └── PinPrompt.cs
│ ├── Cli/
│ │ ├── ArgumentParser.cs
│ │ ├── CommandHelper.cs (YubiKeyManager lifecycle + CTS)
│ │ └── InteractiveMenuBuilder.cs
│ └── Yubico.YubiKit.Cli.Shared.csproj
```

---

## Shared Patterns Found (5/5 CLIs)

### 1. Device Selection (~1000 LOC duplicated)
- `DeviceSelection` record — identical across all 5
- `FindDevicesWithRetryAsync` — same retry loop
- `PromptForDeviceSelectionAsync` — identical interactive prompt
- `FormatFormFactor` / `FormatConnectionType` — identical switch statements
- **Variation:** Connection type filtering differs per CLI (SmartCard-only vs HidFido+SmartCard)

### 2. Output Helpers (~850 LOC duplicated)
- `WriteSuccess`, `WriteError`, `WriteWarning`, `WriteInfo` — identical
- `WriteKeyValue`, `WriteHex`, `WriteBoolValue` — identical
- `ConfirmDangerous`, `ConfirmDestructive` — identical
- `CreateTable` — 4/5 CLIs identical
- **Variation:** OathTool uses plain text (no Spectre.Console)

### 3. Argument Parser (~100 LOC, 3 CLIs)
- `HasFlag`, `GetArgValue`, `GetPositionalArgs` — identical logic

### 4. YubiKeyManager Lifecycle (~50 LOC, 5 CLIs)
- `StartMonitoring()` + `ShutdownAsync()` wrapper
- CancellationTokenSource + Console.CancelKeyPress boilerplate

---

## Extraction Phases

### Phase 1: Foundation (2-3 hours, Risk: Very Low)
1. `DeviceSelection` record
2. `ArgumentParser` (HasFlag, GetArgValue, GetPositionalArgs)
3. `FormFactorFormatter` + `ConnectionTypeFormatter`
4. `ConfirmationPrompts` (ConfirmDangerous, ConfirmDestructive)

**Impact:** ~250 LOC saved, zero risk

### Phase 2: UI/Output Layer (3-4 hours, Risk: Low)
5. `OutputHelpers` (core methods — WriteSuccess/Error/Warning/Info/KeyValue/Hex)
6. `PinPrompt` helpers
7. `CommandHelper` (YubiKeyManager lifecycle + CTS setup)

**Impact:** ~350 LOC saved, minimal risk

### Phase 3: Device Selection (4-6 hours, Risk: Medium)
8. `DeviceSelectorBase` abstract class
9. 5 CLI-specific subclasses (filtering by connection type)

**Impact:** ~1000 LOC saved, requires testing

### Phase 4: Optional
10. `InteractiveMenuBuilder` (builder pattern for Spectre.Console menus)
11. Generic `SessionHelper<TSession>` (device+session creation pattern)

---

## Inconsistencies to Normalize First

| Issue | CLIs Affected | Fix |
|-------|--------------|-----|
| OpenPgpTool uses `v` instead of `✓` for success | OpenPgpTool | Use U+2713 |
| OathTool lacks CancellationToken in entry points | OathTool | Add CTS pattern |
| Non-interactive auto-select varies (some prompt, some auto) | All | Virtual property on base |
| Exception handling: some continue, some exit | All | Standardize per-mode |
| Menu item styling: emoji vs plain text | 3 CLIs | Choose consistent style |

---

## Estimates

| Metric | Value |
|--------|-------|
| Total duplicated LOC | ~2,600 |
| Expected savings | ~2,200 (84%) |
| Total effort | 9-13 hours (phased) |
| Risk | Low (Phase 1-2), Medium (Phase 3) |

---

## Decision Log

- 2026-04-02: DevTeam review completed. All patterns documented. Deferred to future sprint.
- 2026-04-02: Phases 1-3 implemented and committed (`32733e32`). Phase 4 (InteractiveMenuBuilder, SessionHelper) deferred — optional per plan. PlainTextOutputHelpers not created; OathTool retains custom plain-text output by design. Reviewer fixes applied: non-interactive guard, Logger.LogDebug, PromptForTouch rename.
Loading
Loading