Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Build

on:
pull_request:
paths:
- 'src/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/build.yml'
push:
paths:
- 'src/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/build.yml'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
toolchain:
- "1.90"
- stable
os:
- ubuntu-x64
- ubuntu-arm64
include:
- os: ubuntu-x64
runner: ubuntu-24.04
target: x86_64-unknown-linux-gnu
- os: ubuntu-arm64
runner: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: ${{ matrix.toolchain }}
target: ${{ matrix.target }}
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libtss2-dev pkg-config
- run: cargo build --workspace --all-targets --all-features --target ${{ matrix.target }}
48 changes: 48 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Lint (Rust)

on:
pull_request:
paths:
- 'src/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/lint.yml'
push:
paths:
- 'src/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/lint.yml'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
rustfmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
components: rustfmt
- run: cargo fmt --all -- --check

clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
components: clippy
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libtss2-dev pkg-config
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings
2 changes: 2 additions & 0 deletions .github/workflows/spdx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ on:
pull_request:
paths:
- "src/**"
- "tests/**"
- ".github/workflows/spdx.yml"
push:
paths:
- "src/**"
- "tests/**"
- ".github/workflows/spdx.yml"
workflow_dispatch:

Expand Down
60 changes: 60 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Integration Tests

on:
push:
paths:
- 'src/**'
- 'tests/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/test.yml'
pull_request:
paths:
- 'src/**'
- 'tests/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/test.yml'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always

jobs:
integration-test:
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
toolchain:
- "1.90"
- stable
os:
- ubuntu-x64
- ubuntu-arm64
include:
- os: ubuntu-x64
runner: ubuntu-24.04
target: x86_64-unknown-linux-gnu
- os: ubuntu-arm64
runner: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: ${{ matrix.toolchain }}
target: ${{ matrix.target }}
- name: Install dependencies and swtpm
run: |
sudo apt-get update
sudo apt-get install -y libtss2-dev pkg-config swtpm
- name: Run integration tests
run: bash ./tests/run_all.sh
48 changes: 47 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,16 @@ cargo build -r
# => ./target/release/tpm2
```

### Set up TPM device
### Set up a native TPM (hardware or vTPM)

This applies to physical TPM chips and virtual TPMs (vTPMs) exposed by
hypervisors (e.g., QEMU, Hyper-V, Google Cloud vTPM).

> [!CAUTION]
> Operations on a native TPM can affect the entire system — clearing hierarchies,
> changing auth values, or modifying NV storage may break measured boot, disk
> encryption (e.g., BitLocker, LUKS), or remote attestation. Use `swtpm` for
> development and testing unless you specifically need a native TPM.

```bash
# Add current user to tss usergroup
Expand All @@ -54,6 +63,43 @@ ls -l /dev/tpm*
export TPM2TOOLS_TCTI="device:/dev/tpm0"
```

### Set up swtpm (software TPM simulator)

[swtpm](https://github.com/stefanberger/swtpm) provides a TPM 2.0 simulator
that runs entirely in user space. It is safe for development, testing, and CI —
its state is ephemeral and isolated from the host system.

```bash
sudo apt install -y swtpm
```

Start the simulator:

```bash
mkdir -p /tmp/swtpm
swtpm socket \
--tpmstate dir=/tmp/swtpm \
--tpm2 \
--server type=tcp,port=2321 \
--ctrl type=tcp,port=2322 \
--flags startup-clear

# In another terminal:
export TPM2TOOLS_TCTI="swtpm:host=localhost,port=2321"
```

### Run integration tests

The test suite uses `swtpm`. Each test script starts its own simulator instance
automatically — no native TPM is needed.

```bash
sudo apt install -y swtpm # if not already installed

# Build and run all tests
bash tests/run_all.sh
```

## Usage

Under construction.
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ use tss_esapi::attributes::ObjectAttributesBuilder;
use tss_esapi::interface_types::algorithm::PublicAlgorithm;
use tss_esapi::interface_types::ecc::EccCurve;
use tss_esapi::interface_types::key_bits::RsaKeyBits;
use tss_esapi::traits::Marshall;
use tss_esapi::structures::{
EccScheme, HashScheme, KeyDerivationFunctionScheme, Public, PublicBuilder,
PublicEccParametersBuilder, PublicRsaParametersBuilder, RsaExponent, RsaScheme,
};
use tss_esapi::traits::Marshall;

use crate::cli::GlobalOpts;
use crate::context::create_context;
Expand Down
4 changes: 1 addition & 3 deletions src/cmd/startauthsession.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ impl StartAuthSessionCmd {

// Set the audit attribute if --audit-session was requested.
if self.audit_session {
let (attrs, mask) = SessionAttributesBuilder::new()
.with_audit(true)
.build();
let (attrs, mask) = SessionAttributesBuilder::new().with_audit(true).build();
ctx.tr_sess_set_attributes(session, attrs, mask)
.context("failed to set audit attribute on session")?;
}
Expand Down
130 changes: 130 additions & 0 deletions tests/helpers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: Apache-2.0
# Common test helpers for tpm2-cli integration tests.
# Source this file from individual test scripts.

set -euo pipefail

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
export TPM2_BIN="${REPO_ROOT}/target/release/tpm2"
SWTPM_PID=""
SWTPM_PORT=""
SWTPM_CTRL_PORT=""
export TEST_TMPDIR=""

# Colours for output (disabled if not a terminal and not in CI).
if [ -t 1 ] || [ "${CI:-}" = "true" ]; then
GREEN=$'\033[32m'
RED=$'\033[31m'
YELLOW=$'\033[33m'
RESET=$'\033[0m'
else
GREEN="" RED="" YELLOW="" RESET=""
fi

PASS_COUNT=0
FAIL_COUNT=0
SKIP_COUNT=0

pass() {
PASS_COUNT=$((PASS_COUNT + 1))
echo "${GREEN} PASS${RESET}: $1"
}

fail() {
FAIL_COUNT=$((FAIL_COUNT + 1))
echo "${RED} FAIL${RESET}: $1"
if [ -n "${2:-}" ]; then
echo " $2"
fi
if [ "${GITHUB_ACTIONS:-}" = "true" ]; then
echo "::error::FAIL: $1"
fi
}

skip() {
SKIP_COUNT=$((SKIP_COUNT + 1))
echo "${YELLOW} SKIP${RESET}: $1"
if [ "${GITHUB_ACTIONS:-}" = "true" ]; then
echo "::warning::SKIP: $1"
fi
}

summary() {
echo ""
echo "Results: ${GREEN}${PASS_COUNT} passed${RESET}, ${RED}${FAIL_COUNT} failed${RESET}, ${YELLOW}${SKIP_COUNT} skipped${RESET}"
if [ "$FAIL_COUNT" -gt 0 ]; then
return 1
fi
return 0
}

# Start an swtpm simulator and set TPM2TOOLS_TCTI.
start_swtpm() {
TEST_TMPDIR="$(mktemp -d)"
export TEST_TMPDIR

# Pick a random port range to avoid collisions.
SWTPM_PORT=$((20000 + RANDOM % 10000))
SWTPM_CTRL_PORT=$((SWTPM_PORT + 1))

swtpm socket \
--tpmstate dir="$TEST_TMPDIR" \
--tpm2 \
--server type=tcp,port="$SWTPM_PORT" \
--ctrl type=tcp,port="$SWTPM_CTRL_PORT" \
--flags startup-clear &
SWTPM_PID=$!

# Wait for swtpm to be ready.
for _ in $(seq 1 20); do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The wait loop for swtpm has a fixed timeout of 2 seconds (20 * 0.1s). On a heavily loaded CI machine, swtpm might take longer to start up, which could lead to flaky tests when the script fails to connect to the socket. Consider increasing the timeout to make the tests more robust.

Suggested change
for _ in $(seq 1 20); do
for _ in $(seq 1 50); do

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will leave the code as-is until the identified issue actually occurs.

if bash -c "echo >/dev/tcp/localhost/$SWTPM_PORT" 2>/dev/null; then
break
fi
sleep 0.1
done

export TPM2TOOLS_TCTI="swtpm:host=localhost,port=${SWTPM_PORT}"
}

# Stop swtpm and clean up.
stop_swtpm() {
if [ -n "$SWTPM_PID" ]; then
kill "$SWTPM_PID" 2>/dev/null || true
wait "$SWTPM_PID" 2>/dev/null || true
SWTPM_PID=""
fi
if [ -n "$TEST_TMPDIR" ]; then
rm -rf "$TEST_TMPDIR"
TEST_TMPDIR=""
fi
}

trap stop_swtpm EXIT

# Run the tpm2 binary. Suppress INFO log output.
tpm2() {
"$TPM2_BIN" -v Off "$@"
}
export -f tpm2

# Run a test case. Usage: run_test "description" command [args...]
# Captures stdout+stderr; on failure prints them.
run_test() {
local desc="$1"
shift
local output
if output=$("$@" 2>&1); then
pass "$desc"
else
fail "$desc" "$(echo "$output" | head -5)"
fi
}

# Build the binary if needed.
ensure_built() {
if [ ! -x "$TPM2_BIN" ]; then
echo "Building tpm2 binary..."
(cd "$REPO_ROOT" && cargo build --release --quiet)
fi
}
Loading
Loading